diff --git a/algorithms/partitioner/main.cpp b/algorithms/partitioner/main.cpp index 1c1dbebd..6f773697 100644 --- a/algorithms/partitioner/main.cpp +++ b/algorithms/partitioner/main.cpp @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with SBG Partitioner. If not, see . - ******************************************************************************/ +******************************************************************************/ #include #include @@ -31,15 +31,65 @@ #include "kernighan_lin_partitioner.hpp" #include "partition_graph.hpp" #include "partition_metrics_api.hpp" +#include "sbg_partitioner_log.hpp" using namespace std; using namespace sbg_partitioner; + +static void read_configuration_file(const string& filename, PartitionerParams& params) +{ + + // helper function + auto to_bool = [](string& str) { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + std::istringstream is(str); + bool b; + is >> std::boolalpha >> b; + return b; + }; + + ifstream ifs(filename); + string line; + while (std::getline(ifs, line)) { + std::istringstream is_line(line); + std::string key; + if(std::getline(is_line, key, '=')) { + std::string value; + if(std::getline(is_line, value)) { + if (key == "filename") { + params.filename = value; + } else if (key == "partitions") { + params.number_of_partitions = stoi(value); + } else if (key == "imbalance") { + params.epsilon = stof(value); + } else if (key == "multithreading") { + params.enable_multithreading = to_bool(value); + } else if (key == "initial_partition_strategy") { + params.initial_partition_strategy = InitialPartitionStrategy(stoi(value)); + } else if (key == "metrics") { + params.compute_metrics = to_bool(value); + } else if (key == "partitions_directory") { + params.directory = value; + } else { + cerr << "Key " << key << " not found, it will be ignored" << endl; + } + } + } + } +} + + static void usage() { cout << "Usage sbg-partitioner" << endl; cout << endl; + + cout << "-c, --config-filename Path to the configuration file, a file with key/values " + "that represents the partitioner configuration. If a flag and value by configuration " + "file are passed, the flag will be used." + << endl; cout << "-f, --filename Path to the input file, a json file that represents " "the model we want to partitionate." << endl; @@ -66,6 +116,7 @@ static void usage() cout << "SBG Partitioner home page: https://github.com/CIFASIS/sbg-partitioner " << endl; } + static void version() { cout << "SBG Partitioner 1.0.0" << endl; @@ -82,6 +133,7 @@ void sort_before_print(PartitionMap partitions, const SBG::LIB::WeightedSBGraph& cout << "partitions: " << partitions << endl; } + void read_directory(const std::string& name, std::vector& v) { auto path_leaf_string = [](const std::filesystem::directory_entry& entry) { return entry.path().string(); }; @@ -92,136 +144,161 @@ void read_directory(const std::string& name, std::vector& v) std::transform(start, end, std::back_inserter(v), path_leaf_string); } + int main(int argc, char** argv) { int opt; - optional filename = nullopt; - optional directory = nullopt; - optional number_of_partitions = nullopt; - optional output_file; - optional output_sb_graph = nullopt; - optional epsilon = nullopt; - InitialPartitionStrategy initial_partition_strategy = InitialPartitionStrategy::ALL; - bool enable_multithreading = false; - bool compute_metrics = false; - - while (true) { - static struct option long_options[] = {{"filename", required_argument, 0, 'f'}, {"partitions", required_argument, 0, 'p'}, - {"output-file", required_argument, 0, 'g'}, {"output-graph", required_argument, 0, 'o'}, - {"compute-metrics", no_argument, 0, 'm'}, {"directory", required_argument, 0, 'd'}, - {"initial-partition-strategy", required_argument, 0, 'i'}, {"enable-multithreading", no_argument, 0, 't'}, - {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}}; + PartitionerParams params; + // look for configuration file + while (true) + { int option_index = 0; - opt = getopt_long(argc, argv, "f:p:e:o:g:d:i:tmvh:", long_options, &option_index); + static struct option long_options[] = {{"config-filename", required_argument, 0, 'c'}, + {"filename", required_argument, 0, 'f'}, {"partitions", required_argument, 0, 'p'}, + {"output-file", required_argument, 0, 'g'}, {"output-graph", required_argument, 0, 'o'}, + {"compute-metrics", no_argument, 0, 'm'}, {"directory", required_argument, 0, 'd'}, + {"initial-partition-strategy", required_argument, 0, 'i'}, {"enable-multithreading", no_argument, 0, 't'}, + {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}}; + + opt = getopt_long(argc, argv, "c:f:p:e:o:g:d:i:tmvh:", long_options, &option_index); if (opt == EOF) break; switch (opt) { - case 'f': - if (optarg) { - filename = string(optarg); - } - break; + case 'c': + if (optarg) { + params.config_filename = string(optarg); + } + break; - case 'p': - if (optarg) { - number_of_partitions = atoi(optarg); + default: + continue; } - break; + } - case 'o': - if (optarg) { - output_sb_graph = string(optarg); - } - break; + // read configuration file if exists, before reading flags + if (params.config_filename) { + read_configuration_file(*params.config_filename, params); + } + + // reset it to read values again. We reed them again because flags overwrite values from configuration file + optind = 0; + while (true) { + int option_index = 0; + static struct option long_options[] = {{"config-filename", required_argument, 0, 'c'}, + {"filename", required_argument, 0, 'f'}, {"partitions", required_argument, 0, 'p'}, + {"output-file", required_argument, 0, 'g'}, {"output-graph", required_argument, 0, 'o'}, + {"compute-metrics", no_argument, 0, 'm'}, {"directory", required_argument, 0, 'd'}, + {"initial-partition-strategy", required_argument, 0, 'i'}, {"enable-multithreading", no_argument, 0, 't'}, + {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}}; + + opt = getopt_long(argc, argv, "c:f:p:e:o:g:d:i:tmvh:", long_options, &option_index); + if (opt == EOF) break; - case 'g': - if (optarg) { - output_file = string(optarg); - } - break; + switch (opt) { + case 'c': // already read + break; + + case 'f': + if (optarg) { + params.filename = string(optarg); + } + break; - case 'e': - if (optarg) { - epsilon = atof(optarg); - } - break; + case 'p': + if (optarg) { + params.number_of_partitions = atoi(optarg); + } + break; - case 'm': - compute_metrics = true; - break; + case 'o': + if (optarg) { + params.output_sb_graph = string(optarg); + } + break; - case 'd': - if (optarg) { - directory = string(optarg); - } - break; + case 'g': + if (optarg) { + params.output_file = string(optarg); + } + break; - case 'i': - if (optarg) { - initial_partition_strategy = InitialPartitionStrategy(atoi(optarg)); - } - break; + case 'e': + if (optarg) { + params.epsilon = atof(optarg); + } + break; - case 't': - enable_multithreading = true; - break; + case 'm': + params.compute_metrics = true; + break; - case 'v': - version(); - exit(0); + case 'd': + if (optarg) { + params.directory = string(optarg); + } + break; - case 'h': - usage(); - exit(0); + case 'i': + if (optarg) { + params.initial_partition_strategy = InitialPartitionStrategy(atoi(optarg)); + } + break; - case '?': - usage(); - exit(-1); - break; + case 't': + params.enable_multithreading = true; + break; - default: - cout << "opt " << opt << endl; - abort(); + case 'v': + version(); + exit(0); + + case 'h': + usage(); + exit(0); + + case '?': + usage(); + exit(-1); + break; + + default: + abort(); } } - if (not filename or not number_of_partitions) { + if (not params.filename or not params.number_of_partitions) { usage(); exit(1); } - if (not epsilon) { - epsilon = 0.0; - } - - if (*epsilon < 0 or *epsilon > 1) { + if (params.epsilon < 0 or params.epsilon > 1) { usage(); exit(1); } - cout << "filename is " << *filename << endl; - cout << "number of partitions is " << *number_of_partitions << endl; + cout << "filename is " << *params.filename << endl; + cout << "number of partitions is " << *params.number_of_partitions << endl; optional s; - if (output_sb_graph) { + if (params.output_sb_graph) { s = ""; } auto start_build_graph = chrono::high_resolution_clock::now(); - auto sb_graph = build_sb_graph(filename->c_str()); + auto sb_graph = build_sb_graph(params.filename->c_str()); auto end_build_graph = chrono::high_resolution_clock::now(); auto time_to_build_graph = chrono::duration(end_build_graph - start_build_graph).count(); cout << "sb_graph: " << sb_graph << endl; auto start_partitionate = chrono::high_resolution_clock::now(); - auto partitions = best_initial_partition(sb_graph, *number_of_partitions, initial_partition_strategy, enable_multithreading); - kl_sbg_imbalance_partitioner(sb_graph, partitions, *epsilon, enable_multithreading); + auto partitions = best_initial_partition(sb_graph, *params.number_of_partitions, params.initial_partition_strategy, params.enable_multithreading); + kl_sbg_imbalance_partitioner(sb_graph, partitions, params.epsilon, params.enable_multithreading); auto end_partitionate = chrono::high_resolution_clock::now(); auto time_to_partitionate = chrono::duration(end_partitionate - start_partitionate).count(); - if (compute_metrics) { + if (params.compute_metrics) { map metrics; int edge_cut = metrics::edge_cut(partitions, sb_graph); @@ -237,9 +314,9 @@ int main(int argc, char** argv) cout << f << ": " << m << endl; } - if (compute_metrics and directory) { + if (params.compute_metrics and params.directory) { std::vector dir_files; - read_directory(*directory, dir_files); + read_directory(*params.directory, dir_files); for (const auto& f : dir_files) { auto partition_from_file = metrics::read_partition_from_file(f, sb_graph); @@ -263,7 +340,7 @@ int main(int argc, char** argv) cout << "time_to_partitionate = " << time_to_partitionate << " ms" << endl; if (sanity_check_enabled) { - sanity_check(sb_graph, partitions, *number_of_partitions); + sanity_check(sb_graph, partitions, *params.number_of_partitions); } if (s) { diff --git a/algorithms/partitioner/partition_graph.hpp b/algorithms/partitioner/partition_graph.hpp index 4f8592cd..13cb8bc3 100644 --- a/algorithms/partitioner/partition_graph.hpp +++ b/algorithms/partitioner/partition_graph.hpp @@ -25,6 +25,7 @@ #include #include +#include "partitioner_params.hpp" #include "sbg_partitioner_types.hpp" #include "weighted_sb_graph.hpp" @@ -34,15 +35,6 @@ namespace sbg_partitioner { constexpr bool sanity_check_enabled = false; -enum InitialPartitionStrategy { - ALL = 0, - DFS_DISTRIBUTIVE_PREORDER = 1, - DFS_DISTRIBUTIVE_POSTORDER = 2, - DFS_GREEDY_PREORDER = 3, - DFS_GREEDY_POSTORDER =4 -}; - - /// @brief Converts a Partition element into a Set. /// @param partition - A list of SetPiece elements. /// @return A SBG::LIB::Set representation of the Partition element. diff --git a/algorithms/partitioner/partitioner_params.hpp b/algorithms/partitioner/partitioner_params.hpp new file mode 100644 index 00000000..c7ff1d93 --- /dev/null +++ b/algorithms/partitioner/partitioner_params.hpp @@ -0,0 +1,50 @@ +/** + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + +******************************************************************************/ + +#pragma once + +#include +#include + +namespace sbg_partitioner { + + +enum InitialPartitionStrategy { + ALL = 0, + DFS_DISTRIBUTIVE_PREORDER = 1, + DFS_DISTRIBUTIVE_POSTORDER = 2, + DFS_GREEDY_PREORDER = 3, + DFS_GREEDY_POSTORDER =4 +}; + + +struct PartitionerParams +{ + std::optional config_filename = std::nullopt; + std::optional filename = std::nullopt; + std::optional directory = std::nullopt; + std::optional number_of_partitions = std::nullopt; + std::optional output_file; + std::optional output_sb_graph = std::nullopt; + float epsilon = 0.0; + InitialPartitionStrategy initial_partition_strategy = InitialPartitionStrategy::ALL; + bool enable_multithreading = false; + bool compute_metrics = false; +}; + +} \ No newline at end of file