Skip to content

Commit

Permalink
feat(goal strategy): add Hybrid strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
HarukiMoriarty committed Aug 8, 2024
1 parent d407b68 commit 7ba3cb1
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 62 deletions.
2 changes: 1 addition & 1 deletion calmapf/include/graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct Graph {
GraphType get_graph_type(std::string type);
int size() const; // the number of vertices, |V|
Vertex* random_target_vertex(int group);
void fill_goals_list(GoalGenerationType goal_generation_type, std::string goal_real_file, int group, uint goals_m, uint goals_k, uint ngoals);
void _fill_goals_list(int group);
Vertex* get_next_goal(int group, int look_ahead = 1);
};

Expand Down
2 changes: 2 additions & 0 deletions calmapf/include/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ struct Parser {

// Goal settings
uint num_goals;
std::vector<uint> strategy_num_goals;

std::string goals_gen_strategy_input;
GoalGenerationType goals_gen_strategy;

uint goals_max_k;
uint goals_max_m;
std::string real_dist_file_path;
std::string hybrid_percent;

// Agent settings
uint num_agents;
Expand Down
1 change: 1 addition & 0 deletions calmapf/include/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,5 @@ enum class GoalGenerationType {
MK,
Zhang,
Real,
Hybrid,
};
114 changes: 55 additions & 59 deletions calmapf/src/graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ Graph::Graph(Parser* _parser) : parser(_parser)
graph_console->info("Generating goals...");

for (int i = 0; i < group; i++) {
fill_goals_list(parser->goals_gen_strategy, parser->real_dist_file_path, i, parser->goals_max_m, parser->goals_max_k, parser->num_goals);
_fill_goals_list(i);
}
}

Expand All @@ -423,73 +423,69 @@ Vertex* Graph::random_target_vertex(int group) {
return *it;
}

void Graph::fill_goals_list(GoalGenerationType goal_generation_type, std::string goal_real_file, int group_index, uint goals_m, uint goals_k, uint ngoals) {
if (goal_generation_type == GoalGenerationType::MK) {
std::deque<Vertex*> sliding_window;
std::unordered_map<Vertex*, int> goal_count;
std::unordered_set<Vertex*> diff_goals;
uint goals_generated = 0;

while (goals_queue[group_index].size() < (uint(ngoals / group) + 1)) {
if (goals_generated % 1000 == 0) {
graph_console->info("Generated {:5}/{:5} goals.", goals_generated, ngoals);
}

Vertex* selected_goal = random_target_vertex(group_index);
void Graph::_fill_goals_list(int group_index) {
for (uint i = 0; i < parser->strategy_num_goals.size(); i++) {
if (i == 0 && parser->strategy_num_goals[i] != 0) {
std::deque<Vertex*> sliding_window;
std::unordered_map<Vertex*, int> goal_count;
std::unordered_set<Vertex*> diff_goals;

while (goals_queue[group_index].size() < (uint(parser->strategy_num_goals[0] / group) + 1)) {
Vertex* selected_goal = random_target_vertex(group_index);

if (sliding_window.size() == parser->goals_max_m) {
Vertex* removed_goal = sliding_window.front();
sliding_window.pop_front();
goal_count[removed_goal]--;
if (goal_count[removed_goal] == 0) {
goal_count.erase(removed_goal);
diff_goals.erase(removed_goal);
}
}

if (sliding_window.size() == goals_m) {
Vertex* removed_goal = sliding_window.front();
sliding_window.pop_front();
goal_count[removed_goal]--;
if (goal_count[removed_goal] == 0) {
goal_count.erase(removed_goal);
diff_goals.erase(removed_goal);
if (diff_goals.size() == parser->goals_max_k) {
int index = get_random_int(&parser->MT, 0, parser->goals_max_k - 1);
auto it = diff_goals.begin();
std::advance(it, index);
selected_goal = *it;
}
}

if (diff_goals.size() == goals_k) {
int index = get_random_int(&parser->MT, 0, goals_k - 1);
auto it = diff_goals.begin();
std::advance(it, index);
selected_goal = *it;
// Update status
sliding_window.push_back(selected_goal);
goal_count[selected_goal]++;
diff_goals.insert(selected_goal);
goals_queue[group_index].push_back(selected_goal);
goals_delay[group_index].push_back(0);
}

// Update status
sliding_window.push_back(selected_goal);
goal_count[selected_goal]++;
diff_goals.insert(selected_goal);
goals_queue[group_index].push_back(selected_goal);
goals_delay[group_index].push_back(0);
goals_generated++;
}
}
// The generation method that is based on "Zhang, Y., 2016. Correlated storage assignment strategy to reduce travel distance in order picking. IFAC-PapersOnLine, 49(2), pp.30-35."
// A summary of the method.
// 10% of items have a sum of 70% probability to be selected (A-class). 20% of items with 20% probability (B-class), 70% of items with 10% (C-class)
// Assumptions:
// 1. The probability for each item decreases as the item index increases.
// 2. The last item in A-class has the same probability as the first item in B-class.
// 3. The last item in B-class has the same probability as the first item in C-class.
// 4. The sum of the probabilities for all A-class items,B-class items, and C-class items are 70%, 20%, and 10%, correspondingly.
else if (goal_generation_type == GoalGenerationType::Zhang) {
std::vector<double> item_prob = calculate_probabilities(cargo_vertices[group_index].size());
boost::random::discrete_distribution<> dist(item_prob);
for (uint i = 0; i < (ngoals / uint(group) + 1); i++) {
goals_queue[group_index].push_back(cargo_vertices[group_index][dist(parser->MT)]);
goals_delay[group_index].push_back(0);
// The generation method that is based on "Zhang, Y., 2016. Correlated storage assignment strategy to reduce travel distance in order picking. IFAC-PapersOnLine, 49(2), pp.30-35."
// A summary of the method.
// 10% of items have a sum of 70% probability to be selected (A-class). 20% of items with 20% probability (B-class), 70% of items with 10% (C-class)
// Assumptions:
// 1. The probability for each item decreases as the item index increases.
// 2. The last item in A-class has the same probability as the first item in B-class.
// 3. The last item in B-class has the same probability as the first item in C-class.
// 4. The sum of the probabilities for all A-class items,B-class items, and C-class items are 70%, 20%, and 10%, correspondingly.
else if (i == 1 && parser->strategy_num_goals[i] != 0) {
std::vector<double> item_prob = calculate_probabilities(cargo_vertices[group_index].size());
boost::random::discrete_distribution<> dist(item_prob);
for (uint i = 0; i < (parser->strategy_num_goals[1] / uint(group) + 1); i++) {
goals_queue[group_index].push_back(cargo_vertices[group_index][dist(parser->MT)]);
goals_delay[group_index].push_back(0);
}
}
}
else if (goal_generation_type == GoalGenerationType::Real) {
std::vector<float> prob_v = compute_frequency_from_file(goal_real_file);
prob_v.resize(cargo_vertices[group_index].size());
boost::random::discrete_distribution<> dist(prob_v);
for (uint i = 0; i < (ngoals / uint(group) + 1); i++) {
goals_queue[group_index].push_back(cargo_vertices[group_index][dist(parser->MT)]);
goals_delay[group_index].push_back(0);
else if (i == 2 && parser->strategy_num_goals[i] != 0) {
std::vector<float> prob_v = compute_frequency_from_file(parser->real_dist_file_path);
prob_v.resize(cargo_vertices[group_index].size());
boost::random::discrete_distribution<> dist(prob_v);
for (uint i = 0; i < (parser->strategy_num_goals[2] / uint(group) + 1); i++) {
goals_queue[group_index].push_back(cargo_vertices[group_index][dist(parser->MT)]);
goals_delay[group_index].push_back(0);
}
}
}

graph_console->debug("Group {} goals {}", group, goals_queue[group_index].size());
graph_console->info("Group {} goals {}", group, goals_queue[group_index].size());
}

Vertex* Graph::get_next_goal(int group, int look_ahead) {
Expand Down
28 changes: 26 additions & 2 deletions calmapf/src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ Parser::Parser(int argc, char* argv[]) {
program.add_argument("-lan", "--look-ahead-num").help("Number for look-ahead logic. Defaults to 1.").default_value(std::string("1"));
program.add_argument("-ddl", "--delay-deadline-limit").help("Delay deadline limit for task assignment. Defaults to 1.").default_value(std::string("1"));
program.add_argument("-ng", "--num-goals").help("Number of goals to achieve.").required();
program.add_argument("-ggs", "--goals-gen-strategy").help("Strategy for goals generation: MK, Zhang, Real.").required();
program.add_argument("-ggs", "--goals-gen-strategy").help("Strategy for goals generation: MK, Zhang, Real, Hybrid.").required();
program.add_argument("-gmk", "--goals-max-k").help("Maximum 'k' different goals in 'm' segments of all goals. Defaults to 0.").default_value(std::string("0"));
program.add_argument("-gmm", "--goals-max-m").help("Maximum 'k' different goals in 'm' segments of all goals. Defaults to 100.").default_value(std::string("100"));
program.add_argument("-rdfp", "--real-dist-file-path").help("Path to the real distribution data file. Defaults to './data/order_data.csv'.").default_value(std::string("./data/order_data.csv"));
program.add_argument("-hp", "--hybrid-percent").help("The percentage that a certain number of distribution goals appear (e.g. \"90:5:5\"). If not set, every strategy has the same percentage").default_value(std::string("1:1:1"));
program.add_argument("-na", "--num-agents").help("Number of agents to use.").required();
program.add_argument("-ac", "--agent-capacity").help("Capacity of agents.").default_value(std::string("100"));
program.add_argument("-rs", "--random-seed").help("Seed for random number generation. Defaults to 0.").default_value(std::string("0"));
Expand Down Expand Up @@ -51,6 +52,7 @@ Parser::Parser(int argc, char* argv[]) {
goals_max_k = std::stoi(program.get<std::string>("goals-max-k"));
goals_max_m = std::stoi(program.get<std::string>("goals-max-m"));
real_dist_file_path = program.get<std::string>("real-dist-file-path");
hybrid_percent = program.get<std::string>("hybrid-percent");

num_agents = std::stoi(program.get<std::string>("num-agents"));
agent_capacity = std::stoi(program.get<std::string>("agent-capacity"));
Expand All @@ -75,7 +77,6 @@ Parser::Parser(int argc, char* argv[]) {
// Print
_print();
}

void Parser::_post_parse() {
// Set log level
if (debug_log) parser_console->set_level(spdlog::level::debug);
Expand Down Expand Up @@ -106,12 +107,34 @@ void Parser::_post_parse() {
exit(1);
}
goals_gen_strategy = GoalGenerationType::MK;
strategy_num_goals.push_back(num_goals);
strategy_num_goals.push_back(0);
strategy_num_goals.push_back(0);
}
else if (goals_gen_strategy_input == "Zhang") {
goals_gen_strategy = GoalGenerationType::Zhang;
strategy_num_goals.push_back(0);
strategy_num_goals.push_back(num_goals);
strategy_num_goals.push_back(0);
}
else if (goals_gen_strategy_input == "Real") {
goals_gen_strategy = GoalGenerationType::Real;
strategy_num_goals.push_back(0);
strategy_num_goals.push_back(0);
strategy_num_goals.push_back(num_goals);
}
else if (goals_gen_strategy_input == "Hybrid") {
goals_gen_strategy = GoalGenerationType::Hybrid;
std::vector<int> percentages;
std::stringstream ss(hybrid_percent);
std::string item;
while (std::getline(ss, item, ':')) {
percentages.push_back(std::stoi(item));
}
int sum = std::accumulate(percentages.begin(), percentages.end(), 0);
for (int percentage : percentages) {
strategy_num_goals.push_back(num_goals * percentage / sum);
}
}
else {
parser_console->error("Invalid goals_generation strategy specified.");
Expand Down Expand Up @@ -148,6 +171,7 @@ void Parser::_print() {
else if (goals_gen_strategy == GoalGenerationType::Real) {
parser_console->info("Real disy file: {}", real_dist_file_path);
}
parser_console->info("Strategy percent: {}", strategy_num_goals);
parser_console->info("Seed: {}", random_seed);
parser_console->info("Time limit (sec): {}", time_limit_sec);
parser_console->info("Step file: {}", output_step_file);
Expand Down

0 comments on commit 7ba3cb1

Please sign in to comment.