diff --git a/libs/libarchfpga/src/device_grid.cpp b/libs/libarchfpga/src/device_grid.cpp index 993d445c27c..f96f1f0ca28 100644 --- a/libs/libarchfpga/src/device_grid.cpp +++ b/libs/libarchfpga/src/device_grid.cpp @@ -1,14 +1,16 @@ #include "device_grid.h" +#include + DeviceGrid::DeviceGrid(std::string grid_name, vtr::NdMatrix grid) - : name_(grid_name) - , grid_(grid) { + : name_(std::move(grid_name)) + , grid_(std::move(grid)) { count_instances(); } DeviceGrid::DeviceGrid(std::string grid_name, vtr::NdMatrix grid, std::vector limiting_res) - : DeviceGrid(grid_name, grid) { - limiting_resources_ = limiting_res; + : DeviceGrid(std::move(grid_name), std::move(grid)) { + limiting_resources_ = std::move(limiting_res); } size_t DeviceGrid::num_instances(t_physical_tile_type_ptr type, int layer_num) const { diff --git a/libs/libvtrutil/src/vtr_ndmatrix.h b/libs/libvtrutil/src/vtr_ndmatrix.h index c3a4692edea..dc69c7f60ba 100644 --- a/libs/libvtrutil/src/vtr_ndmatrix.h +++ b/libs/libvtrutil/src/vtr_ndmatrix.h @@ -288,7 +288,7 @@ class NdMatrixBase { data_ = std::make_unique(size()); } - ///@brief Returns the size of the matrix (number of elements) calucated from the current dimensions + ///@brief Returns the size of the matrix (number of elements) calculated from the current dimensions size_t calc_size() const { ///@brief Size is the product of all dimension sizes size_t cnt = dim_size(0); @@ -310,7 +310,7 @@ class NdMatrixBase { * * Examples: * - * //A 2-dimensional matrix with indicies [0..4][0..9] + * //A 2-dimensional matrix with indices [0..4][0..9] * NdMatrix m1({5,10}); * * //Accessing an element @@ -319,17 +319,17 @@ class NdMatrixBase { * //Setting an element * m1[2][8] = 0; * - * //A 3-dimensional matrix with indicies [0..4][0..9][0..19] + * //A 3-dimensional matrix with indices [0..4][0..9][0..19] * NdMatrix m2({5,10,20}); * - * //A 2-dimensional matrix with indicies [0..4][0..9], with all entries + * //A 2-dimensional matrix with indices [0..4][0..9], with all entries * //initialized to 42 * NdMatrix m3({5,10}, 42); * * //Filling all entries with value 101 * m3.fill(101); * - * //Resizing an existing matrix (all values reset to default constucted value) + * //Resizing an existing matrix (all values reset to default constructed value) * m3.resize({5,5}) * * //Resizing an existing matrix (all elements set to value 88) diff --git a/vpr/src/base/CheckSetup.cpp b/vpr/src/base/CheckSetup.cpp index 44d382938a3..4bc78d116fb 100644 --- a/vpr/src/base/CheckSetup.cpp +++ b/vpr/src/base/CheckSetup.cpp @@ -31,33 +31,39 @@ void CheckSetup(const t_packer_opts& PackerOpts, "This is allowed, but strange, and circuit speed will suffer.\n"); } - if ((false == Timing.timing_analysis_enabled) + if (!Timing.timing_analysis_enabled && (PlacerOpts.place_algorithm.is_timing_driven())) { /* May work, not tested */ VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Timing analysis must be enabled for timing-driven placement.\n"); } - if (!PlacerOpts.doPlacement && ("" != PlacerOpts.constraints_file)) { + if (!PlacerOpts.doPlacement && (!PlacerOpts.constraints_file.empty())) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "A block location file requires that placement is enabled.\n"); } - if (PlacerOpts.place_static_move_prob.size() != NUM_PL_MOVE_TYPES) { + if (PlacerOpts.place_algorithm.is_timing_driven() && + PlacerOpts.place_static_move_prob.size() > NUM_PL_MOVE_TYPES) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, - "The number of placer move probabilities should equal to the total number of supported moves. %d\n", PlacerOpts.place_static_move_prob.size()); + "The number of provided placer move probabilities (%d) should equal or less than the total number of supported moves (%d).\n", + PlacerOpts.place_static_move_prob.size(), + NUM_PL_MOVE_TYPES); } - if (PlacerOpts.place_static_notiming_move_prob.size() != NUM_PL_NONTIMING_MOVE_TYPES) { + if (!PlacerOpts.place_algorithm.is_timing_driven() && + PlacerOpts.place_static_move_prob.size() > NUM_PL_NONTIMING_MOVE_TYPES) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, - "The number of placer non timing move probabilities should equal to the total number of supported moves. %d\n", PlacerOpts.place_static_notiming_move_prob.size()); + "The number of placer non timing move probabilities (%d) should equal to or less than the total number of supported moves (%d).\n", + PlacerOpts.place_static_move_prob.size(), + NUM_PL_MOVE_TYPES); } if (RouterOpts.doRouting) { if (!Timing.timing_analysis_enabled && (DEMAND_ONLY != RouterOpts.base_cost_type && DEMAND_ONLY_NORMALIZED_LENGTH != RouterOpts.base_cost_type)) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, - "base_cost_type must be demand_only or demand_only_normailzed_length when timing analysis is disabled.\n"); + "base_cost_type must be demand_only or demand_only_normalized_length when timing analysis is disabled.\n"); } } diff --git a/vpr/src/base/SetupGrid.cpp b/vpr/src/base/SetupGrid.cpp index 3569f5bff1f..11ac2e52694 100644 --- a/vpr/src/base/SetupGrid.cpp +++ b/vpr/src/base/SetupGrid.cpp @@ -31,8 +31,8 @@ using vtr::t_formula_data; static DeviceGrid auto_size_device_grid(const std::vector& grid_layouts, const std::map& minimum_instance_counts, float maximum_device_utilization); static std::vector grid_overused_resources(const DeviceGrid& grid, std::map instance_counts); -static bool grid_satisfies_instance_counts(const DeviceGrid& grid, std::map instance_counts, float maximum_utilization); -static DeviceGrid build_device_grid(const t_grid_def& grid_def, size_t width, size_t height, bool warn_out_of_range = true, std::vector limiting_resources = std::vector()); +static bool grid_satisfies_instance_counts(const DeviceGrid& grid, const std::map& instance_counts, float maximum_utilization); +static DeviceGrid build_device_grid(const t_grid_def& grid_def, size_t width, size_t height, bool warn_out_of_range = true, const std::vector& limiting_resources = std::vector()); static void CheckGrid(const DeviceGrid& grid); @@ -316,8 +316,8 @@ static std::vector grid_overused_resources(const Devic return overused_resources; } -static bool grid_satisfies_instance_counts(const DeviceGrid& grid, std::map instance_counts, float maximum_utilization) { - //Are the resources satisified? +static bool grid_satisfies_instance_counts(const DeviceGrid& grid, const std::map& instance_counts, float maximum_utilization) { + //Are the resources satisfied? auto overused_resources = grid_overused_resources(grid, instance_counts); if (!overused_resources.empty()) { @@ -335,7 +335,7 @@ static bool grid_satisfies_instance_counts(const DeviceGrid& grid, std::map limiting_resources) { +static DeviceGrid build_device_grid(const t_grid_def& grid_def, size_t grid_width, size_t grid_height, bool warn_out_of_range, const std::vector& limiting_resources) { if (grid_def.grid_type == GridDefType::FIXED) { if (grid_def.width != int(grid_width) || grid_def.height != int(grid_height)) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, @@ -754,7 +754,7 @@ static void CheckGrid(const DeviceGrid& grid) { } } -float calculate_device_utilization(const DeviceGrid& grid, std::map instance_counts) { +float calculate_device_utilization(const DeviceGrid& grid, const std::map& instance_counts) { //Record the resources of the grid std::map grid_resources; for (int layer_num = 0; layer_num < grid.get_num_layers(); ++layer_num) { diff --git a/vpr/src/base/SetupGrid.h b/vpr/src/base/SetupGrid.h index 4dd80c28539..cfde1e523d8 100644 --- a/vpr/src/base/SetupGrid.h +++ b/vpr/src/base/SetupGrid.h @@ -27,7 +27,7 @@ DeviceGrid create_device_grid(std::string layout_name, const std::vector instance_counts); +float calculate_device_utilization(const DeviceGrid& grid, const std::map& instance_counts); /** * @brief Returns the effective size of the device diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index b431d26feae..99368f3093d 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -661,8 +661,8 @@ static void SetupPlacerOpts(const t_options& Options, t_placer_opts* PlacerOpts) PlacerOpts->effort_scaling = Options.place_effort_scaling; PlacerOpts->timing_update_type = Options.timing_update_type; PlacerOpts->enable_analytic_placer = Options.enable_analytic_placer; - PlacerOpts->place_static_move_prob = Options.place_static_move_prob; - PlacerOpts->place_static_notiming_move_prob = Options.place_static_notiming_move_prob; + PlacerOpts->place_static_move_prob = vtr::vector(Options.place_static_move_prob.value().begin(), + Options.place_static_move_prob.value().end()); PlacerOpts->place_high_fanout_net = Options.place_high_fanout_net; PlacerOpts->place_bounding_box_mode = Options.place_bounding_box_mode; PlacerOpts->RL_agent_placement = Options.RL_agent_placement; diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 72e02317fd9..bd181078c34 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2032,23 +2032,17 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio place_grp.add_argument(args.place_static_move_prob, "--place_static_move_prob") .help( - "The percentage probabilities of different moves in Simulated Annealing placement." - "This option is only effective for timing-driven placement." - "The numbers listed are interpreted as the percentage probabilities of {uniformMove, MedianMove, CentroidMove, WeightedCentroid, WeightedMedian, Timing feasible Region(TFR), Critical UniformMove}, in that order.") + "The percentage probabilities of different moves in Simulated Annealing placement. " + "For non-timing-driven placement, only the first 3 probabilities should be provided. " + "For timing-driven placement, all probabilities should be provided. " + "When the number of provided probabilities is less then the number of move types, zero probability " + "is assumed." + "The numbers listed are interpreted as the percentage probabilities of {UniformMove, MedianMove, CentroidMove, " + "WeightedCentroid, WeightedMedian, Critical UniformMove, Timing feasible Region(TFR)}, in that order.") .nargs('+') - .default_value({"100", "0", "0", "0", "0", "0", "0"}) - + .default_value({"100"}) .show_in(argparse::ShowIn::HELP_ONLY); - place_grp.add_argument(args.place_static_notiming_move_prob, "--place_static_notiming_move_prob") - .help( - "The Probability of different non timing move in Simulated Annealing." - "This option is only effective for nontiming driven placement." - " The numbers listed are interpreted as the percentage probabilities of {uniformMove, MedianMove, CentroidMove}, in that order.") - .nargs('+') - .default_value({"100", "0", "0"}) - - .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.place_high_fanout_net, "--place_high_fanout_net") .help( diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 540df6f1321..26505c13bc9 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -126,7 +126,6 @@ struct t_options { argparse::ArgValue place_delta_delay_matrix_calculation_method; argparse::ArgValue enable_analytic_placer; argparse::ArgValue> place_static_move_prob; - argparse::ArgValue> place_static_notiming_move_prob; argparse::ArgValue place_high_fanout_net; argparse::ArgValue place_bounding_box_mode; diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index f0e7c1b258a..fc77c8aedd0 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -89,11 +89,9 @@ enum class ScreenUpdatePriority { /* Values large enough to be way out of range for any data, but small enough * to allow a small number to be added to them without going out of range. */ #define HUGE_POSITIVE_FLOAT 1.e30 -#define HUGE_NEGATIVE_FLOAT -1.e30 /* Used to avoid floating-point errors when comparing values close to 0 */ #define EPSILON 1.e-15 -#define NEGATIVE_EPSILON -1.e-15 #define FIRST_ITER_WIRELENTH_LIMIT 0.85 /* If used wirelength exceeds this value in first iteration of routing, do not route */ @@ -110,12 +108,10 @@ constexpr auto INVALID_BLOCK_ID = ClusterBlockId(-2); * and maps it to the complex logic blocks found in the architecture ******************************************************************************/ -#define NO_CLUSTER -1 -#define NEVER_CLUSTER -2 -#define NOT_VALID -10000 /* Marks gains that aren't valid */ +#define NOT_VALID (-10000) /* Marks gains that aren't valid */ /* Ensure no gain can ever be this negative! */ #ifndef UNDEFINED -# define UNDEFINED -1 +# define UNDEFINED (-1) #endif enum class e_router_lookahead { @@ -550,9 +546,8 @@ enum class e_timing_update_type { ****************************************************************************/ /* Values of number of placement available move types */ -#define NUM_PL_MOVE_TYPES 7 -#define NUM_PL_NONTIMING_MOVE_TYPES 3 -#define NUM_PL_1ST_STATE_MOVE_TYPES 4 +constexpr int NUM_PL_MOVE_TYPES = 7; +constexpr int NUM_PL_NONTIMING_MOVE_TYPES = 3; /* Timing data structures end */ enum sched_type { @@ -1155,6 +1150,8 @@ enum class e_place_delta_delay_algorithm { DIJKSTRA_EXPANSION, }; +enum class e_move_type; + /** * @brief Various options for the placer. * @@ -1253,8 +1250,7 @@ struct t_placer_opts { std::string write_placement_delay_lookup; std::string read_placement_delay_lookup; - std::vector place_static_move_prob; - std::vector place_static_notiming_move_prob; + vtr::vector place_static_move_prob; bool RL_agent_placement; bool place_agent_multistate; bool place_checkpointing; diff --git a/vpr/src/place/RL_agent_util.cpp b/vpr/src/place/RL_agent_util.cpp index c0ee94cc7ce..89dd60d20a6 100644 --- a/vpr/src/place/RL_agent_util.cpp +++ b/vpr/src/place/RL_agent_util.cpp @@ -1,27 +1,25 @@ #include "RL_agent_util.h" +#include "static_move_generator.h" #include "manual_move_generator.h" -void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, const t_placer_opts& placer_opts, int move_lim) { - if (placer_opts.RL_agent_placement == false) { - if (placer_opts.place_algorithm.is_timing_driven()) { - VTR_LOG("Using static probabilities for choosing each move type\n"); - VTR_LOG("Probability of Uniform_move : %f \n", placer_opts.place_static_move_prob[0]); - VTR_LOG("Probability of Median_move : %f \n", placer_opts.place_static_move_prob[1]); - VTR_LOG("Probability of Centroid_move : %f \n", placer_opts.place_static_move_prob[2]); - VTR_LOG("Probability of Weighted_centroid_move : %f \n", placer_opts.place_static_move_prob[3]); - VTR_LOG("Probability of Weighted_median_move : %f \n", placer_opts.place_static_move_prob[4]); - VTR_LOG("Probability of Timing_feasible_region_move : %f \n", placer_opts.place_static_move_prob[5]); - VTR_LOG("Probability of Critical_uniform_move : %f \n", placer_opts.place_static_move_prob[6]); - move_generator = std::make_unique(placer_opts.place_static_move_prob); - move_generator2 = std::make_unique(placer_opts.place_static_move_prob); - } else { //Non-timing driven placement - VTR_LOG("Using static probabilities for choosing each move type\n"); - VTR_LOG("Probability of Uniform_move : %f \n", placer_opts.place_static_notiming_move_prob[0]); - VTR_LOG("Probability of Median_move : %f \n", placer_opts.place_static_notiming_move_prob[1]); - VTR_LOG("Probability of Centroid_move : %f \n", placer_opts.place_static_notiming_move_prob[2]); - move_generator = std::make_unique(placer_opts.place_static_notiming_move_prob); - move_generator2 = std::make_unique(placer_opts.place_static_notiming_move_prob); +void create_move_generators(std::unique_ptr& move_generator, + std::unique_ptr& move_generator2, + const t_placer_opts& placer_opts, + int move_lim) { + if (!placer_opts.RL_agent_placement) { // RL agent is disabled + auto move_types = placer_opts.place_static_move_prob; + move_types.resize((int)e_move_type::NUMBER_OF_AUTO_MOVES, 0.0f); + + VTR_LOG("Using static probabilities for choosing each move type\n"); + for (const auto move_type : placer_opts.place_static_move_prob.keys()) { + const std::string& move_name = move_type_to_string(move_type); + VTR_LOG("Probability of %s : %f \n", + move_name.c_str(), + placer_opts.place_static_move_prob[move_type]); } + + move_generator = std::make_unique(placer_opts.place_static_move_prob); + move_generator2 = std::make_unique(placer_opts.place_static_move_prob); } else { //RL based placement /* For the non timing driven placement: the agent has a single state * * - Available moves are (Uniform / Median / Centroid) * @@ -42,27 +40,35 @@ void create_move_generators(std::unique_ptr& move_generator, std: * only move type. * * This state is activated late in the anneal and in the Quench */ - int num_1st_state_avail_moves = placer_opts.place_algorithm.is_timing_driven() ? NUM_PL_1ST_STATE_MOVE_TYPES : NUM_PL_NONTIMING_MOVE_TYPES; - int num_2nd_state_avail_moves = placer_opts.place_algorithm.is_timing_driven() ? NUM_PL_MOVE_TYPES : NUM_PL_NONTIMING_MOVE_TYPES; + std::vector first_state_avail_moves {e_move_type::UNIFORM, e_move_type::MEDIAN, e_move_type::CENTROID}; + if (placer_opts.place_algorithm.is_timing_driven()) { + first_state_avail_moves.push_back(e_move_type::W_CENTROID); + } + + std::vector second_state_avail_moves {e_move_type::UNIFORM, e_move_type::MEDIAN, e_move_type::CENTROID}; + if (placer_opts.place_algorithm.is_timing_driven()) { + second_state_avail_moves.insert(second_state_avail_moves.end(), + {e_move_type::W_CENTROID, e_move_type::W_MEDIAN, e_move_type::CRIT_UNIFORM, e_move_type::FEASIBLE_REGION}); + } if (placer_opts.place_agent_algorithm == E_GREEDY) { std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2; //agent's 1st state if (placer_opts.place_agent_space == e_agent_space::MOVE_BLOCK_TYPE) { VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move and block types\n"); - karmed_bandit_agent1 = std::make_unique(num_1st_state_avail_moves, + karmed_bandit_agent1 = std::make_unique(first_state_avail_moves, e_agent_space::MOVE_BLOCK_TYPE, placer_opts.place_agent_epsilon); } else { VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move types\n"); - karmed_bandit_agent1 = std::make_unique(num_1st_state_avail_moves, + karmed_bandit_agent1 = std::make_unique(first_state_avail_moves, e_agent_space::MOVE_TYPE, placer_opts.place_agent_epsilon); } karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); move_generator = std::make_unique(karmed_bandit_agent1); //agent's 2nd state - karmed_bandit_agent2 = std::make_unique(num_2nd_state_avail_moves, + karmed_bandit_agent2 = std::make_unique(second_state_avail_moves, e_agent_space::MOVE_TYPE, placer_opts.place_agent_epsilon); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); @@ -72,17 +78,17 @@ void create_move_generators(std::unique_ptr& move_generator, std: //agent's 1st state if (placer_opts.place_agent_space == e_agent_space::MOVE_BLOCK_TYPE) { VTR_LOG("Using simple RL 'Softmax agent' for choosing move and block types\n"); - karmed_bandit_agent1 = std::make_unique(num_1st_state_avail_moves, + karmed_bandit_agent1 = std::make_unique(first_state_avail_moves, e_agent_space::MOVE_BLOCK_TYPE); } else { VTR_LOG("Using simple RL 'Softmax agent' for choosing move types\n"); - karmed_bandit_agent1 = std::make_unique(num_1st_state_avail_moves, + karmed_bandit_agent1 = std::make_unique(first_state_avail_moves, e_agent_space::MOVE_TYPE); } karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); move_generator = std::make_unique(karmed_bandit_agent1); //agent's 2nd state - karmed_bandit_agent2 = std::make_unique(num_2nd_state_avail_moves, + karmed_bandit_agent2 = std::make_unique(second_state_avail_moves, e_agent_space::MOVE_TYPE); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); move_generator2 = std::make_unique(karmed_bandit_agent2); @@ -90,28 +96,38 @@ void create_move_generators(std::unique_ptr& move_generator, std: } } -void assign_current_move_generator(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, e_agent_state agent_state, const t_placer_opts& placer_opts, bool in_quench, std::unique_ptr& current_move_generator) { +void assign_current_move_generator(std::unique_ptr& move_generator, + std::unique_ptr& move_generator2, + e_agent_state agent_state, + const t_placer_opts& placer_opts, + bool in_quench, + std::unique_ptr& current_move_generator) { if (in_quench) { - if (placer_opts.place_quench_algorithm.is_timing_driven() && placer_opts.place_agent_multistate == true) + if (placer_opts.place_quench_algorithm.is_timing_driven() && placer_opts.place_agent_multistate) current_move_generator = std::move(move_generator2); else current_move_generator = std::move(move_generator); } else { - if (agent_state == EARLY_IN_THE_ANNEAL || placer_opts.place_agent_multistate == false) + if (agent_state == e_agent_state::EARLY_IN_THE_ANNEAL || !placer_opts.place_agent_multistate) current_move_generator = std::move(move_generator); else current_move_generator = std::move(move_generator2); } } -void update_move_generator(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, e_agent_state agent_state, const t_placer_opts& placer_opts, bool in_quench, std::unique_ptr& current_move_generator) { +void update_move_generator(std::unique_ptr& move_generator, + std::unique_ptr& move_generator2, + e_agent_state agent_state, + const t_placer_opts& placer_opts, + bool in_quench, + std::unique_ptr& current_move_generator) { if (in_quench) { - if (placer_opts.place_quench_algorithm.is_timing_driven() && placer_opts.place_agent_multistate == true) + if (placer_opts.place_quench_algorithm.is_timing_driven() && placer_opts.place_agent_multistate) move_generator2 = std::move(current_move_generator); else move_generator = std::move(current_move_generator); } else { - if (agent_state == EARLY_IN_THE_ANNEAL || placer_opts.place_agent_multistate == false) + if (agent_state == e_agent_state::EARLY_IN_THE_ANNEAL || !placer_opts.place_agent_multistate) move_generator = std::move(current_move_generator); else move_generator2 = std::move(current_move_generator); diff --git a/vpr/src/place/RL_agent_util.h b/vpr/src/place/RL_agent_util.h index ebfee697850..00c073dea89 100644 --- a/vpr/src/place/RL_agent_util.h +++ b/vpr/src/place/RL_agent_util.h @@ -1,12 +1,11 @@ #ifndef RL_AGENT_UTIL_H #define RL_AGENT_UTIL_H -#include "static_move_generator.h" -#include "simpleRL_move_generator.h" -#include "manual_move_generator.h" +#include "move_generator.h" + //enum represents the available agent states -enum e_agent_state { +enum class e_agent_state { EARLY_IN_THE_ANNEAL, LATE_IN_THE_ANNEAL }; @@ -19,15 +18,28 @@ enum e_agent_state { * It returns a unique pointer for each move generator in move_generator and move_generator2 * move_lim: represents the num of moves per temp. */ -void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, const t_placer_opts& placer_opts, int move_lim); +void create_move_generators(std::unique_ptr& move_generator, + std::unique_ptr& move_generator2, + const t_placer_opts& placer_opts, + int move_lim); /** * @brief copy one of the available move_generators to be the current move_generator that would be used in the placement based on the placer_options and the agent state */ -void assign_current_move_generator(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, e_agent_state agent_state, const t_placer_opts& placer_opts, bool in_quench, std::unique_ptr& current_move_generator); +void assign_current_move_generator(std::unique_ptr& move_generator, + std::unique_ptr& move_generator2, + e_agent_state agent_state, + const t_placer_opts& placer_opts, + bool in_quench, + std::unique_ptr& current_move_generator); /** * @ brief move the updated current_move_generator to its original move_Generator structure based on he placer_options and the agent state */ -void update_move_generator(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, e_agent_state agent_state, const t_placer_opts& placer_opts, bool in_quench, std::unique_ptr& current_move_generator); +void update_move_generator(std::unique_ptr& move_generator, + std::unique_ptr& move_generator2, + e_agent_state agent_state, + const t_placer_opts& placer_opts, + bool in_quench, + std::unique_ptr& current_move_generator); #endif diff --git a/vpr/src/place/move_generator.h b/vpr/src/place/move_generator.h index 83791bbcf9b..bc20143da07 100644 --- a/vpr/src/place/move_generator.h +++ b/vpr/src/place/move_generator.h @@ -23,15 +23,15 @@ struct MoveOutcomeStats { /** * @brief A Struct to hold statistics about the different move types * - * blk_type_moves: the block type index of each proposed move (e.g. [0..NUM_PL_MOVE_TYPES * (agent_available_types.size()-1)]) - * accepted_moves: the number of accepted moves of each move and block type (e.g. [0..NUM_PL_MOVE_TYPES * (agent_available_types.size()-1)] ) - * rejected_moves: the number of rejected moves of each move and block type (e.g. [0..NUM_PL_MOVE_TYPES * (agent_available_types.size()-1)] ) + * blk_type_moves: the block type index of each proposed move (e.g. [0..NUM_PL_MOVE_TYPES][agent_available_types.size()-1)]) + * accepted_moves: the number of accepted moves of each move and block type (e.g. [0..NUM_PL_MOVE_TYPES][agent_available_types.size()-1)] ) + * rejected_moves: the number of rejected moves of each move and block type (e.g. [0..NUM_PL_MOVE_TYPES][agent_available_types.size()-1)] ) * */ struct MoveTypeStat { - std::vector blk_type_moves; - std::vector accepted_moves; - std::vector rejected_moves; + vtr::NdMatrix blk_type_moves; + vtr::NdMatrix accepted_moves; + vtr::NdMatrix rejected_moves; }; /** @@ -50,7 +50,7 @@ class MoveGenerator { * This function proposes a new move and updates blocks affected and move_type accorrdingly. The function interface is general * to match the parameters needed by all move generators * - * @param blocks_affectedt: the output of the move + * @param blocks_affected: the output of the move * @param proposed_action: Contains the move type and block type. If the block type is specified, * the proposed move swaps instances of the given block type. Otherwise, the selected block type * by the move generator is written to proposed_action.logical_blk_type_index. diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 23a64cafd78..40425bf18b5 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -28,7 +28,7 @@ void report_aborted_moves() { if (f_move_abort_reasons.empty()) { VTR_LOG(" No moves aborted\n"); } - for (auto kv : f_move_abort_reasons) { + for (const auto& kv : f_move_abort_reasons) { VTR_LOG(" %s: %zu\n", kv.first.c_str(), kv.second); } } @@ -1028,7 +1028,7 @@ void compressed_grid_to_loc(t_logical_block_type_ptr blk_type, auto& grid = g_vpr_ctx.device().grid; auto to_type = grid.get_physical_type({grid_loc.x, grid_loc.y, grid_loc.layer_num}); - //Each x/y location contains only a single type, so we can pick a random z (capcity) location + //Each x/y location contains only a single type, so we can pick a random z (capacity) location auto& compatible_sub_tiles = compressed_block_grid.compatible_sub_tile_num(to_type->index); int sub_tile = compatible_sub_tiles[vtr::irand((int)compatible_sub_tiles.size() - 1)]; diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 059528c6415..efe21d52122 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -543,8 +543,7 @@ static void print_resources_utilization(); static void print_placement_swaps_stats(const t_annealing_state& state); -static void print_placement_move_types_stats( - const MoveTypeStat& move_type_stat); +static void print_placement_move_types_stats(const MoveTypeStat& move_type_stat); /*****************************************************************************/ void try_place(const Netlist<>& net_list, @@ -936,9 +935,9 @@ void try_place(const Netlist<>& net_list, //allocate move type statistics vectors MoveTypeStat move_type_stat; - move_type_stat.blk_type_moves.resize(device_ctx.logical_block_types.size() * placer_opts.place_static_move_prob.size(), 0); - move_type_stat.accepted_moves.resize(device_ctx.logical_block_types.size() * placer_opts.place_static_move_prob.size(), 0); - move_type_stat.rejected_moves.resize(device_ctx.logical_block_types.size() * placer_opts.place_static_move_prob.size(), 0); + move_type_stat.blk_type_moves.resize({device_ctx.logical_block_types.size(), (int)e_move_type::NUMBER_OF_AUTO_MOVES}, 0); + move_type_stat.accepted_moves.resize({device_ctx.logical_block_types.size(), (int)e_move_type::NUMBER_OF_AUTO_MOVES}, 0); + move_type_stat.rejected_moves.resize({device_ctx.logical_block_types.size(), (int)e_move_type::NUMBER_OF_AUTO_MOVES}, 0); /* Get the first range limiter */ first_rlim = (float)max(device_ctx.grid.width() - 1, @@ -982,7 +981,7 @@ void try_place(const Netlist<>& net_list, #endif /* ENABLE_ANALYTIC_PLACE */ //RL agent state definition - e_agent_state agent_state = EARLY_IN_THE_ANNEAL; + e_agent_state agent_state = e_agent_state::EARLY_IN_THE_ANNEAL; std::unique_ptr current_move_generator; @@ -1012,7 +1011,7 @@ void try_place(const Netlist<>& net_list, //see if we should save the current placement solution as a checkpoint if (placer_opts.place_checkpointing - && agent_state == LATE_IN_THE_ANNEAL) { + && agent_state == e_agent_state::LATE_IN_THE_ANNEAL) { save_placement_checkpoint_if_needed(placement_checkpoint, timing_info, costs, critical_path.delay()); } @@ -1046,9 +1045,9 @@ void try_place(const Netlist<>& net_list, if (placer_opts.place_algorithm.is_timing_driven() && placer_opts.place_agent_multistate - && agent_state == EARLY_IN_THE_ANNEAL) { + && agent_state == e_agent_state::EARLY_IN_THE_ANNEAL) { if (state.alpha < 0.85 && state.alpha > 0.6) { - agent_state = LATE_IN_THE_ANNEAL; + agent_state = e_agent_state::LATE_IN_THE_ANNEAL; VTR_LOG("Agent's 2nd state: \n"); } } @@ -1725,7 +1724,7 @@ static e_move_result try_swap(const t_annealing_state* state, } if (proposed_action.logical_blk_type_index != -1) { //if the agent proposed the block type, then collect the block type stat - ++move_type_stat.blk_type_moves[(proposed_action.logical_blk_type_index * (placer_opts.place_static_move_prob.size())) + (int)proposed_action.move_type]; + ++move_type_stat.blk_type_moves[proposed_action.logical_blk_type_index][(int)proposed_action.move_type]; } LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1876,7 +1875,7 @@ static e_move_result try_swap(const t_annealing_state* state, commit_move_blocks(blocks_affected); if (proposed_action.logical_blk_type_index != -1) { //if the agent proposed the block type, then collect the block type stat - ++move_type_stat.accepted_moves[(proposed_action.logical_blk_type_index * (placer_opts.place_static_move_prob.size())) + (int)proposed_action.move_type]; + ++move_type_stat.accepted_moves[proposed_action.logical_blk_type_index][(int)proposed_action.move_type]; } if (noc_opts.noc) { commit_noc_costs(); @@ -1927,7 +1926,7 @@ static e_move_result try_swap(const t_annealing_state* state, } if (proposed_action.logical_blk_type_index != -1) { //if the agent proposed the block type, then collect the block type stat - ++move_type_stat.rejected_moves[(proposed_action.logical_blk_type_index * (placer_opts.place_static_move_prob.size())) + (int)proposed_action.move_type]; + ++move_type_stat.rejected_moves[proposed_action.logical_blk_type_index][(int)proposed_action.move_type]; } /* Revert the traffic flow routes within the NoC*/ if (noc_opts.noc) { @@ -4350,10 +4349,7 @@ static void print_placement_swaps_stats(const t_annealing_state& state) { num_swap_aborted, 100 * abort_rate); } -static void print_placement_move_types_stats( - const MoveTypeStat& move_type_stat) { - float moves, accepted, rejected, aborted; - +static void print_placement_move_types_stats(const MoveTypeStat& move_type_stat) { VTR_LOG("\n\nPlacement perturbation distribution by block and move type: \n"); VTR_LOG( @@ -4363,11 +4359,12 @@ static void print_placement_move_types_stats( VTR_LOG( "------------------ ----------------- ---------------- ---------------- --------------- ------------ \n"); - float total_moves = 0; - for (int blk_type_move : move_type_stat.blk_type_moves) { - total_moves += blk_type_move; + int total_moves = 0; + for (size_t i = 0; i < move_type_stat.blk_type_moves.size(); ++i) { + total_moves += move_type_stat.blk_type_moves.get(i); } + auto& device_ctx = g_vpr_ctx.device(); auto& cluster_ctx = g_vpr_ctx.clustering(); int count = 0; @@ -4381,14 +4378,13 @@ static void print_placement_move_types_stats( } count = 0; - for (int imove = 0; imove < num_of_avail_moves; imove++) { const auto& move_name = move_type_to_string(e_move_type(imove)); - moves = move_type_stat.blk_type_moves[itype.index * num_of_avail_moves + imove]; + int moves = move_type_stat.blk_type_moves[itype.index][imove]; if (moves != 0) { - accepted = move_type_stat.accepted_moves[itype.index * num_of_avail_moves + imove]; - rejected = move_type_stat.rejected_moves[itype.index * num_of_avail_moves + imove]; - aborted = moves - (accepted + rejected); + int accepted = move_type_stat.accepted_moves[itype.index][imove]; + int rejected = move_type_stat.rejected_moves[itype.index][imove]; + int aborted = moves - (accepted + rejected); if (count == 0) { VTR_LOG("%-18.20s", itype.name); } else { @@ -4396,9 +4392,9 @@ static void print_placement_move_types_stats( } VTR_LOG( " %-22.20s %-16.2f %-15.2f %-14.2f %-13.2f\n", - move_name.c_str(), 100 * moves / total_moves, - 100 * accepted / moves, 100 * rejected / moves, - 100 * aborted / moves); + move_name.c_str(), 100.0f * (float)moves / (float)total_moves, + 100.0f * (float)accepted / (float)moves, 100.0f * (float)rejected / (float)moves, + 100.0f * (float)aborted / (float)moves); } count++; } diff --git a/vpr/src/place/simpleRL_move_generator.cpp b/vpr/src/place/simpleRL_move_generator.cpp index 17753d66a88..172178f49ce 100644 --- a/vpr/src/place/simpleRL_move_generator.cpp +++ b/vpr/src/place/simpleRL_move_generator.cpp @@ -2,6 +2,7 @@ #include "globals.h" #include #include +#include #include "vtr_random.h" #include "vtr_time.h" @@ -14,9 +15,13 @@ static float scaled_clipped_exp(float x) { return std::exp(std::min(1000 * x, fl * RL move generator implementation * * * * */ -e_create_move SimpleRLMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, t_propose_action& proposed_action, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities) { +e_create_move SimpleRLMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, + t_propose_action& proposed_action, + float rlim, + const t_placer_opts& placer_opts, + const PlacerCriticalities* criticalities) { proposed_action = karmed_bandit_agent->propose_action(); - return avail_moves[(int)proposed_action.move_type]->propose_move(blocks_affected, proposed_action, rlim, placer_opts, criticalities); + return all_moves[proposed_action.move_type]->propose_move(blocks_affected, proposed_action, rlim, placer_opts, criticalities); } void SimpleRLMoveGenerator::process_outcome(double reward, e_reward_function reward_fun) { @@ -28,13 +33,14 @@ void SimpleRLMoveGenerator::process_outcome(double reward, e_reward_function rew * K-Armed bandit agent implementation * * * * */ -KArmedBanditAgent::KArmedBanditAgent(size_t num_moves, e_agent_space agent_space) - : num_available_moves_(num_moves) +KArmedBanditAgent::KArmedBanditAgent(std::vector available_moves, e_agent_space agent_space) + : available_moves_(std::move(available_moves)) , propose_blk_type_(agent_space == e_agent_space::MOVE_BLOCK_TYPE) { std::vector available_logical_block_types = get_available_logical_blk_types_(); num_available_types_ = available_logical_block_types.size(); - num_available_actions_ = propose_blk_type_ ? (num_available_moves_ * num_available_types_) : num_available_moves_; + size_t num_available_moves = available_moves_.size(); + num_available_actions_ = propose_blk_type_ ? (num_available_moves * num_available_types_) : num_available_moves; action_logical_blk_type_.clear(); @@ -64,7 +70,7 @@ e_move_type KArmedBanditAgent::action_to_move_type_(const size_t action_idx) { e_move_type move_type = e_move_type::INVALID_MOVE; if (action_idx < num_available_actions_) { - move_type = (e_move_type)(action_idx % num_available_moves_); + move_type = available_moves_[action_idx % available_moves_.size()]; } return move_type; @@ -72,7 +78,7 @@ e_move_type KArmedBanditAgent::action_to_move_type_(const size_t action_idx) { int KArmedBanditAgent::action_to_blk_type_(const size_t action_idx) { if (propose_blk_type_) { - return action_logical_blk_type_.at(action_idx / num_available_moves_); + return action_logical_blk_type_.at(action_idx / available_moves_.size()); } else { // the agent doesn't select the move type return -1; } @@ -101,8 +107,10 @@ std::vector KArmedBanditAgent::get_available_logical_blk_types_() { void KArmedBanditAgent::process_outcome(double reward, e_reward_function reward_fun) { ++num_action_chosen_[last_action_]; - if (reward_fun == RUNTIME_AWARE || reward_fun == WL_BIASED_RUNTIME_AWARE) - reward /= time_elapsed_[last_action_ % num_available_moves_]; + if (reward_fun == RUNTIME_AWARE || reward_fun == WL_BIASED_RUNTIME_AWARE) { + e_move_type move_type = action_to_move_type_(last_action_); + reward /= time_elapsed_[move_type]; + } //Determine step size float step = 0.; @@ -150,13 +158,13 @@ void KArmedBanditAgent::set_step(float gamma, int move_lim) { } else { // // For an exponentially weighted average the fraction of total weight applied - // to moves which occured > K moves ago is: + // to moves which occurred > K moves ago is: // // gamma = (1 - alpha)^K // // If we treat K as the number of moves per temperature (move_lim) then gamma - // is the fraction of weight applied to moves which occured > move_lim moves ago, - // and given a target gamma we can explicitly calcualte the alpha step-size + // is the fraction of weight applied to moves which occurred > move_lim moves ago, + // and given a target gamma we can explicitly calculate the alpha step-size // required by the agent: // // alpha = 1 - e^(log(gamma) / K) @@ -174,8 +182,8 @@ int KArmedBanditAgent::agent_to_phy_blk_type(const int idx) { * E-greedy agent implementation * * * * */ -EpsilonGreedyAgent::EpsilonGreedyAgent(size_t num_moves, e_agent_space agent_space, float epsilon) - : KArmedBanditAgent(num_moves, agent_space) { +EpsilonGreedyAgent::EpsilonGreedyAgent(std::vector available_moves, e_agent_space agent_space, float epsilon) + : KArmedBanditAgent(std::move(available_moves), agent_space) { set_epsilon(epsilon); init_q_scores_(); } @@ -223,7 +231,7 @@ t_propose_action EpsilonGreedyAgent::propose_action() { action_to_blk_type_(last_action_)}; //Check the move type to be a valid move - VTR_ASSERT((size_t)proposed_action.move_type < num_available_moves_); + VTR_ASSERT_SAFE(std::find(available_moves_.begin(), available_moves_.end(), proposed_action.move_type) != available_moves_.end()); return proposed_action; } @@ -249,8 +257,8 @@ void EpsilonGreedyAgent::set_epsilon_action_prob() { * Softmax agent implementation * * * * */ -SoftmaxAgent::SoftmaxAgent(size_t num_moves, e_agent_space agent_space) - : KArmedBanditAgent(num_moves, agent_space) { +SoftmaxAgent::SoftmaxAgent(std::vector available_moves, e_agent_space agent_space) + : KArmedBanditAgent(std::move(available_moves), agent_space) { init_q_scores_(); } @@ -297,7 +305,7 @@ t_propose_action SoftmaxAgent::propose_action() { action_to_blk_type_(last_action_)}; //Check the move type to be a valid move - VTR_ASSERT((size_t)proposed_action.move_type < num_available_moves_); + VTR_ASSERT_SAFE(std::find(available_moves_.begin(), available_moves_.end(), proposed_action.move_type) != available_moves_.end()); return proposed_action; } @@ -318,7 +326,7 @@ void SoftmaxAgent::set_block_ratio_() { blk_type.index = agent_to_phy_blk_type(itype); auto num_blocks = cluster_ctx.clb_nlist.blocks_per_type(blk_type).size(); block_type_ratio_[itype] = (float)num_blocks / num_total_blocks; - block_type_ratio_[itype] /= num_available_moves_; + block_type_ratio_[itype] /= available_moves_.size(); } } @@ -333,7 +341,7 @@ void SoftmaxAgent::set_action_prob_() { for (size_t i = 0; i < num_available_actions_; ++i) { if (propose_blk_type_) { //calculate block type index based on its location on q_table - int blk_ratio_index = (int)i / num_available_moves_; + int blk_ratio_index = (int)i / available_moves_.size(); action_prob_[i] = (exp_q_[i] / sum_q) * block_type_ratio_[blk_ratio_index]; } else { action_prob_[i] = (exp_q_[i] / sum_q); @@ -347,7 +355,7 @@ void SoftmaxAgent::set_action_prob_() { [sum_prob](float x) { return x * (1 / sum_prob); }); } else { std::transform(action_prob_.begin(), action_prob_.end(), action_prob_.begin(), - [sum_prob, this](float x) { return x + ((1.0 - sum_prob) / this->num_available_moves_); }); + [sum_prob, this](float x) { return x + ((1.0 - sum_prob) / this->available_moves_.size()); }); } // calculate the accumulative action probability of each action diff --git a/vpr/src/place/simpleRL_move_generator.h b/vpr/src/place/simpleRL_move_generator.h index de108313023..babd0423813 100644 --- a/vpr/src/place/simpleRL_move_generator.h +++ b/vpr/src/place/simpleRL_move_generator.h @@ -14,7 +14,7 @@ */ class KArmedBanditAgent { public: - KArmedBanditAgent(size_t num_moves, e_agent_space agent_space); + KArmedBanditAgent(std::vector available_moves, e_agent_space agent_space); virtual ~KArmedBanditAgent() = default; /** @@ -84,18 +84,18 @@ class KArmedBanditAgent { inline int agent_to_phy_blk_type(int idx); protected: - float exp_alpha_ = -1; //Step size for q_ updates (< 0 implies use incremental average) - size_t num_available_moves_; //Number of move types that agent can choose from to perform - size_t num_available_types_; //Number of block types that exist in the netlest. Agent may not choose the block type. - size_t num_available_actions_; //Total number of available actions - bool propose_blk_type_ = false; //Check if agent should propose both move and block type or only move type - std::vector num_action_chosen_; //Number of times each arm has been pulled (n) - std::vector q_; //Estimated value of each arm (Q) - size_t last_action_; //type of the last action (move type) proposed + float exp_alpha_ = -1; //Step size for q_ updates (< 0 implies use incremental average) + std::vector available_moves_; //All available moves from which the agent can choose + size_t num_available_types_; //Number of block types that exist in the netlist. Agent may not choose the block type. + size_t num_available_actions_; //Total number of available actions + bool propose_blk_type_ = false; //Check if agent should propose both move and block type or only move type + std::vector num_action_chosen_; //Number of times each arm has been pulled (n) + std::vector q_; //Estimated value of each arm (Q) + size_t last_action_; //type of the last action (move type) proposed /* Ratios of the average runtime to calculate each move type */ /* These ratios are useful for different reward functions * * The vector is calculated by averaging many runs on different circuits */ - std::vector time_elapsed_{1.0, 3.6, 5.4, 2.5, 2.1, 0.8, 2.2}; + const vtr::vector time_elapsed_{1.0, 3.6, 5.4, 2.5, 2.1, 0.8, 2.2}; FILE* agent_info_file_ = nullptr; @@ -121,7 +121,7 @@ class KArmedBanditAgent { */ class EpsilonGreedyAgent : public KArmedBanditAgent { public: - EpsilonGreedyAgent(size_t num_moves, e_agent_space agent_space, float epsilon); + EpsilonGreedyAgent(std::vector available_moves, e_agent_space agent_space, float epsilon); ~EpsilonGreedyAgent() override; t_propose_action propose_action() override; //Returns the type of the next action as well as the block type the agent wishes to perform @@ -160,10 +160,10 @@ class EpsilonGreedyAgent : public KArmedBanditAgent { */ class SoftmaxAgent : public KArmedBanditAgent { public: - SoftmaxAgent(size_t num_moves, e_agent_space agent_space); + SoftmaxAgent(std::vector available_moves, e_agent_space agent_space); ~SoftmaxAgent() override; - //void process_outcome(double reward, std::string reward_fun) override; //Updates the agent based on the reward of the last proposed action + t_propose_action propose_action() override; //Returns the type of the next action as well as the block type the agent wishes to perform private: @@ -200,8 +200,8 @@ class SoftmaxAgent : public KArmedBanditAgent { */ class SimpleRLMoveGenerator : public MoveGenerator { private: - std::vector> avail_moves; // list of pointers to the available move generators (the different move types) - std::unique_ptr karmed_bandit_agent; // a pointer to the specific agent used (e.g. Softmax) + vtr::vector> all_moves; // list of pointers to all move generators (the different move types) + std::unique_ptr karmed_bandit_agent; // a pointer to the specific agent used (e.g. Softmax) public: // constructor using a pointer to the agent used @@ -219,7 +219,11 @@ class SimpleRLMoveGenerator : public MoveGenerator { explicit SimpleRLMoveGenerator(std::unique_ptr& agent); // Updates affected_blocks with the proposed move, while respecting the current rlim - e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, t_propose_action& proposed_action, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities) override; + e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, + t_propose_action& proposed_action, + float rlim, + const t_placer_opts& placer_opts, + const PlacerCriticalities* criticalities) override; // Receives feedback about the outcome of the previously proposed move void process_outcome(double reward, e_reward_function reward_fun) override; @@ -227,15 +231,15 @@ class SimpleRLMoveGenerator : public MoveGenerator { template SimpleRLMoveGenerator::SimpleRLMoveGenerator(std::unique_ptr& agent) { - avail_moves.resize((int)e_move_type::NUMBER_OF_AUTO_MOVES); - - avail_moves[(int)e_move_type::UNIFORM] = std::make_unique(); - avail_moves[(int)e_move_type::MEDIAN] = std::make_unique(); - avail_moves[(int)e_move_type::CENTROID] = std::make_unique(); - avail_moves[(int)e_move_type::W_CENTROID] = std::make_unique(); - avail_moves[(int)e_move_type::W_MEDIAN] = std::make_unique(); - avail_moves[(int)e_move_type::CRIT_UNIFORM] = std::make_unique(); - avail_moves[(int)e_move_type::FEASIBLE_REGION] = std::make_unique(); + all_moves.resize((int)e_move_type::NUMBER_OF_AUTO_MOVES); + + all_moves[e_move_type::UNIFORM] = std::make_unique(); + all_moves[e_move_type::MEDIAN] = std::make_unique(); + all_moves[e_move_type::CENTROID] = std::make_unique(); + all_moves[e_move_type::W_CENTROID] = std::make_unique(); + all_moves[e_move_type::W_MEDIAN] = std::make_unique(); + all_moves[e_move_type::CRIT_UNIFORM] = std::make_unique(); + all_moves[e_move_type::FEASIBLE_REGION] = std::make_unique(); karmed_bandit_agent = std::move(agent); } diff --git a/vpr/src/place/static_move_generator.cpp b/vpr/src/place/static_move_generator.cpp index e927a95caaa..b5920f1ffeb 100644 --- a/vpr/src/place/static_move_generator.cpp +++ b/vpr/src/place/static_move_generator.cpp @@ -1,42 +1,61 @@ + #include "static_move_generator.h" -#include "globals.h" -#include + +#include "median_move_generator.h" +#include "weighted_median_move_generator.h" +#include "weighted_centroid_move_generator.h" +#include "feasible_region_move_generator.h" +#include "uniform_move_generator.h" +#include "critical_uniform_move_generator.h" +#include "centroid_move_generator.h" #include "vtr_random.h" #include "vtr_assert.h" -StaticMoveGenerator::StaticMoveGenerator(const std::vector& prob) { - avail_moves.emplace_back(std::make_unique()); - avail_moves.emplace_back(std::make_unique()); - avail_moves.emplace_back(std::make_unique()); - avail_moves.emplace_back(std::make_unique()); - avail_moves.emplace_back(std::make_unique()); - avail_moves.emplace_back(std::make_unique()); - avail_moves.emplace_back(std::make_unique()); +StaticMoveGenerator::StaticMoveGenerator(const vtr::vector& move_probs) { + all_moves.resize((int)e_move_type::NUMBER_OF_AUTO_MOVES); - initialize_move_prob(prob); + all_moves[e_move_type::UNIFORM] = std::make_unique(); + all_moves[e_move_type::MEDIAN] = std::make_unique(); + all_moves[e_move_type::CENTROID] = std::make_unique(); + all_moves[e_move_type::W_CENTROID] = std::make_unique(); + all_moves[e_move_type::W_MEDIAN] = std::make_unique(); + all_moves[e_move_type::CRIT_UNIFORM] = std::make_unique(); + all_moves[e_move_type::FEASIBLE_REGION] = std::make_unique(); + + initialize_move_prob(move_probs); } -void StaticMoveGenerator::initialize_move_prob(const std::vector& prob) { - cumm_move_probs.push_back(prob[0]); - for (size_t i = 1; i < prob.size(); i++) { - cumm_move_probs.push_back(prob[i] + cumm_move_probs[i - 1]); +void StaticMoveGenerator::initialize_move_prob(const vtr::vector& move_probs) { + cumm_move_probs.resize((int)e_move_type::NUMBER_OF_AUTO_MOVES); + std::fill(cumm_move_probs.begin(), cumm_move_probs.end(), 0.0f); + + for(auto move_type : move_probs.keys()) { + cumm_move_probs[move_type] = move_probs[move_type]; } - total_prob = cumm_move_probs[cumm_move_probs.size() - 1]; + std::partial_sum(cumm_move_probs.begin(), cumm_move_probs.end(), cumm_move_probs.begin()); + + total_prob = cumm_move_probs.back(); } -e_create_move StaticMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, t_propose_action& proposed_action, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities) { +e_create_move StaticMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, + t_propose_action& proposed_action, + float rlim, + const t_placer_opts& placer_opts, + const PlacerCriticalities* criticalities) { float rand_num = vtr::frand() * total_prob; - for (size_t i = 0; i < cumm_move_probs.size(); i++) { - if (rand_num <= cumm_move_probs[i]) { - proposed_action.move_type = (e_move_type)i; - return avail_moves[i]->propose_move(blocks_affected, proposed_action, rlim, placer_opts, criticalities); + + for (auto move_type : cumm_move_probs.keys()) { + if (rand_num <= cumm_move_probs[move_type]) { + proposed_action.move_type = move_type; + return all_moves[move_type]->propose_move(blocks_affected, proposed_action, rlim, placer_opts, criticalities); } } - VTR_ASSERT_MSG(false, vtr::string_fmt("During static probability move selection, random number (%g) exceeded total expected probabaility (%g)", rand_num, total_prob).c_str()); + + VTR_ASSERT_MSG(false, vtr::string_fmt("During static probability move selection, random number (%g) exceeded total expected probability (%g)", rand_num, total_prob).c_str()); //Unreachable - proposed_action.move_type = (e_move_type)(avail_moves.size() - 1); - return avail_moves[avail_moves.size() - 1]->propose_move(blocks_affected, proposed_action, rlim, placer_opts, criticalities); + proposed_action.move_type = e_move_type::INVALID_MOVE; + return e_create_move::ABORT; } diff --git a/vpr/src/place/static_move_generator.h b/vpr/src/place/static_move_generator.h index e971dd02954..56b42eea671 100644 --- a/vpr/src/place/static_move_generator.h +++ b/vpr/src/place/static_move_generator.h @@ -1,29 +1,28 @@ #ifndef VPR_STATIC_MOVE_GEN_H #define VPR_STATIC_MOVE_GEN_H + #include "move_generator.h" -#include "median_move_generator.h" -#include "weighted_median_move_generator.h" -#include "weighted_centroid_move_generator.h" -#include "feasible_region_move_generator.h" -#include "uniform_move_generator.h" -#include "critical_uniform_move_generator.h" -#include "centroid_move_generator.h" -#include /** - * @brief a special move generator class that cointrols the different move types by assigning a fixed probability for each move type + * @brief a special move generator class that controls the different move types by assigning a fixed probability for each move type * * It is useful to give VPR user the ability to assign static probabilities for different move types. */ class StaticMoveGenerator : public MoveGenerator { private: - std::vector> avail_moves; //list of pointers to the different available move type generators - std::vector cumm_move_probs; // accumulative probabilities for different move types - float total_prob; // sum of the input probabilities from the use - void initialize_move_prob(const std::vector& prob); + vtr::vector> all_moves; // list of pointers to the different available move type generators + vtr::vector cumm_move_probs; // accumulative probabilities for different move types + float total_prob; // sum of the input probabilities from the use + + void initialize_move_prob(const vtr::vector& move_probs); public: - StaticMoveGenerator(const std::vector& prob); - e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, t_propose_action& proposed_action, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities) override; + StaticMoveGenerator(const vtr::vector& move_probs); + + e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, + t_propose_action& proposed_action, + float rlim, + const t_placer_opts& placer_opts, + const PlacerCriticalities* criticalities) override; }; #endif