From e7d2ec631ed2b4bb039874c4c61035bcef01fdec Mon Sep 17 00:00:00 2001 From: Jaime Arias Almeida <arias@lipn.univ-paris13.fr> Date: Sun, 15 Jan 2023 13:15:01 +0100 Subject: [PATCH] add cli --- libs/parser/src/Net.cpp | 7 +- src/main.cpp | 287 +++++++++++++++++++++------------------- 2 files changed, 153 insertions(+), 141 deletions(-) diff --git a/libs/parser/src/Net.cpp b/libs/parser/src/Net.cpp index 7df6c53..c533c2d 100644 --- a/libs/parser/src/Net.cpp +++ b/libs/parser/src/Net.cpp @@ -111,12 +111,11 @@ RelaCausal* net::rech_couple_cause(Transition t) { return r; } -/*------------------------------calcul l’ensemble - * d’observation-----------------------------------*/ +/*-------------------- calcul l’ensemble d’observation-----------------------*/ set<int> net::calcul1() { set<int> unobs; - int l = transitions.size(); - for (int i = 0; i < l; i++) { + + for (int i = 0; i < transitions.size(); i++) { Transition t = transitions[i]; t.visited = true; if (t.post.size() >= 1) { diff --git a/src/main.cpp b/src/main.cpp index 87bbd5e..2266fa7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include <time.h> +#include <CLI11.hpp> #include <algorithm> #include <cmath> #include <fstream> @@ -8,154 +9,166 @@ #include <map> #include <string> -using namespace std; #include "Net.hpp" #include "RdPBDD.hpp" #include "bdd.h" #include "fdd.h" +using namespace std; + double getTime() { return (double)clock() / (double)CLOCKS_PER_SEC; } -int main(int argc, char** argv) { - if (argc <= 2 or std::string(argv[1]).find("help") != -1) - cout << "/**************************************************************/" - "\n/******************** help " - "********************/ \n -To generate the reachability graph: use " - "the option -r <filename.net>. \n -To generate test paths covering " - "the given observable transitions t1,t2...tn: use the option -o " - "<filename.net> <fileobs.txt >. \n -To generate test paths using " - "structural analysis: use the option -a <filename.net>\n -To " - "generate the conplete SOG corresponding to obs trans: use the " - "option -c " - "<filename.net>/" - "**************************************************************/" - << endl; - - else { - string option = std::string(argv[1]); - cout << "nom fichier source " << endl; - cout << "Fichier net : " << argv[2] << endl; - net R(argv[2]); - cout << "parser...done" << endl; - set<vector<int>> abstrait; - int pp = string(argv[2]).find(".n"); - int ps = string(argv[2]).rfind("/"); - string nom = string(argv[2]).substr(ps + 1, pp - ps - 1); - double d, tps; - int b = 32; - map<int, int> obs; - set<int> unobs; - set<vector<int>> chemins; - - d = getTime(); - - // option -a for structural analysis - if (!option.compare("-a") or !option.compare("-o") or - !option.compare("-c")) { - if (!option.compare("-a") or !option.compare("-c")) { - unobs = R.calcul1(); - for (long unsigned int i = 0; i < R.transitions.size(); i++) { - if ((unobs.find(i)) == unobs.end()) { - obs.insert({i, 1}); - } - } - } - - if (!option.compare("-o")) { // lire les trnansitions observable a partie - // d'un fichier - ifstream flux(argv[3]); - string ligne; - if (flux) { - while (getline(flux, ligne)) { - int tr = - stoi(ligne.substr(1)); // le ligne sous forme de t1 prendre le1 - obs.insert({tr, 1}); - } - } - for (long unsigned int i = 0; i < R.transitions.size(); i++) { - if ((obs.find(i)) == obs.end()) { - unobs.insert(i); - } - } - } - - RdPBDD DR(R, obs, unobs, b); - cout << "RdpBDD construit" << endl; - MDGraph g; - - if (!option.compare("-c")) { - DR.complete_sog(g, obs); - g.generate_Dotfile_of_reachability_graph("complete_sog_" + nom); - cout << " Result in ./result/complete_sog_" + nom + ".dot" << endl; - } - - ofstream monFlux("./result/result_no_opt_" + nom + ".txt"); - - int n = 0; - if (!option.compare("-a") or !option.compare("-o")) { - chemins = DR.chem_obs(g, obs); - monFlux << "le nombre de chemins observés: " << chemins.size() << endl; - for (auto i : chemins) { - n++; - monFlux << "le " << n << " ch: " << i.size() << " tr." - << endl; // result in file result/result_no_opt.txt" - - vector<int> chem_abs; - chem_abs = DR.chem_abs(i, g); - - abstrait.insert(chem_abs); - } - - tps = getTime() - d; - - cout << " Temps de construction du graphe d'observation " << tps - << endl; - g.printCompleteInformation(); - cout << "transition " << R.transitions.size() << endl; - cout << "places " << R.places.size() << endl; - cout << "trans obs " << obs.size() << endl; - cout << "--- abstract path ----" << endl; - set<int> visit; - float somme = 0; - float ecart = 0; - - for (auto i : abstrait) { - for (auto tr : i) { - visit.insert(tr); - } - - somme = somme + i.size(); - } - - float moy = somme / (abstrait.size()); - cout << "nb de chemins: " << abstrait.size() << endl; - cout << "nb moyen de transitions par chemin: " << moy << endl; - - for (auto i : abstrait) { - ecart = ecart + (((i.size() - moy) * (i.size() - moy))); - } - - ecart = pow((ecart / abstrait.size()), 0.5); - cout << "ecart type: " << ecart << endl; - - cout << "nb of covered transitions: " << visit.size() << endl; - cout << " Result in " - << "./result/result_no_opt_" + nom + ".txt" << endl; - return 0; - } +void print_stats(const set<vector<int>> abstract_paths) { + int sum_transtions = 0; + set<int> transitions; + for (auto path : abstract_paths) { + for (auto tr : path) { + transitions.insert(tr); } + sum_transtions += path.size(); + } + + int nb_paths = abstract_paths.size(); + float average = sum_transtions / (nb_paths); + + float std_deviation = 0; + for (auto path : abstract_paths) { + std_deviation += pow(path.size() - average, 2); + } + std_deviation = sqrt(std_deviation / nb_paths); + + cout << "# abstract paths: " << nb_paths << endl; + cout << "average # of transitions per abstract path: " << average << endl; + cout << "standard deviation: " << std_deviation << endl; + cout << "# covered transitions: " << transitions.size() << endl; +} + +string get_model_name(const string& filename) { + int pp = filename.find(".n") + 1; + int ps = filename.rfind("/") + 1; + string name = filename.substr(ps, pp - ps - 1); + return name; +} + +net load_net(const string& filename) { + cout << "Parsing net: " << filename << " ... "; + net R(filename.c_str()); + cout << "done" << endl; + + return R; +} - else if (!option.compare("-r")) { - for (long unsigned int i = 0; i < R.transitions.size(); i++) { - obs.insert({i, 1}); - } +void generate_paths(const string& file, const string& output_folder, + int bound = 32) { + net model = load_net(file); + string model_name = get_model_name(file); - RdPBDD DR(R, obs, unobs, b); - MDGraph g; - DR.complete_sog(g, obs); - g.generate_Dotfile_of_reachability_graph("reach_" + nom); - return 0; + map<int, int> obs; + set<vector<int>> abstrait; + MDGraph g; + + double d = getTime(); + + // compute the unobservable transitions of the model using the pattern + set<int> unobs = model.calcul1(); + + // compute the observable transitions + for (long unsigned int i = 0; i < model.transitions.size(); i++) { + if ((unobs.find(i)) == unobs.end()) { + obs.insert({i, 1}); } } + + // build the SOG + cout << "Building SOG ..."; + RdPBDD DR(model, obs, unobs, bound); + cout << "done"; + + // compute the observable paths + set<vector<int>> chemins = DR.chem_obs(g, obs); + + string output_file = output_folder + "/no_optimal_" + model_name + ".txt"; + ofstream monFlux(output_file); + monFlux << "le nombre de chemins observés: " << chemins.size() << endl; + + int n = 1; + for (auto i : chemins) { + monFlux << "le " << n << " ch: " << i.size() << " tr." << endl; + + // add abstract paths + abstrait.insert(DR.chem_abs(i, g)); + n++; + } + + // time for generating the paths + double tps = getTime() - d; + + // print SOG information + g.printCompleteInformation(); + cout << "\n# transition: " << model.transitions.size() << endl; + cout << "# places: " << model.places.size() << endl; + cout << "# observable transitions: " << obs.size() << endl << endl; + + // print stats + print_stats(abstrait); + + // print time + cout << "\nTime for computing all the paths: " << tps << " seconds" << endl; + cout << "Saving results in " << output_file << endl; +} +/****************************************************************************** + * Main function + ******************************************************************************/ +int main(int argc, char** argv) { + CLI::App app{ + "sogMBT: Symbolic Observation Graph-Based Generation of Test Paths"}; + app.require_subcommand(1); + + string input_file = ""; + app.add_option("--input-net", input_file, "Petri net file") + ->type_name("Path") + ->required() + ->check(CLI::ExistingFile); + + string output_folder = ""; + app.add_option("--output-folder", output_folder, "output folder") + ->type_name("Path") + ->required() + ->check(CLI::ExistingDirectory); + + CLI::App* reach = + app.add_subcommand("reachability", + "Generate the reachability graph in dot format") + ->fallthrough(); + + CLI::App* sog = + app.add_subcommand( + "sog", + "Generate the full SOG corresponding to observable transitions") + ->fallthrough(); + + CLI::App* generate = + app.add_subcommand( + "generate", + "Generate test path using a transition coverage criteria") + ->fallthrough(); + + std::string obs_file; + generate->add_option("--transitions", obs_file, "Observable transitions") + ->type_name("Path") + ->check(CLI::ExistingFile); + + bool all{false}; + generate->add_flag("--all", all, + "Cover all observable transitions (default: false)"); + + // reach->callback([&]() {}); + // sog->callback([&]() {}); + generate->callback([&]() { generate_paths(input_file, output_folder); }); + + // parse arguments + CLI11_PARSE(app, argc, argv); + + return 0; } -- GitLab