Commit 4d2101a6 authored by Gijs van Cuyck's avatar Gijs van Cuyck

cleaned up code in general.

removed finished todos.
removed unused code.
created batch script to run the algorithm on a set of files sequentialy.
parent 3515babf
......@@ -42,3 +42,6 @@ com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
#project specific
benchmarks/
\ No newline at end of file
......@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.8)
project(complete_ads)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-static-libgcc -static-libstdc++")
set(SOURCE_FILES main.cpp src/main_test.cpp)
add_subdirectory("lib")
add_subdirectory("src")
\ No newline at end of file
do_copy
\ No newline at end of file
File added
@echo off
IF EXIST "do_copy" copy ..\cmake-build-debug\main.exe main.exe
for /r %%i in (..\test_benchmarks\*) do (
echo running agorithm for %%~nxi
main.exe -a -f %%i
echo.
)
pause
\ No newline at end of file
......@@ -27,8 +27,8 @@ struct mealy {
std::vector<std::vector<edge>> graph;
size_t graph_size = 0;
size_t input_size = 0;
size_t output_size = 0;
input input_size = 0;
output output_size = 0;
};
inline bool is_complete(const mealy & m){
......@@ -42,7 +42,7 @@ inline bool is_complete(const mealy & m){
inline bool defined(mealy const & m, state s, input i) {
if (s >= m.graph.size()) return false;
if (i >= m.graph[s].size()) return false;
if (m.graph[s][i].to == state(-1) || m.graph[s][i].out == output(-1)) return false;
if (m.graph[s][i].to == state(-1)) return false;
return true;
}
......
#include "reachability.hpp"
#include "mealy.hpp"
#include <map>
#include <queue>
#include <vector>
using namespace std;
mealy reachable_submachine(const mealy& in, state start) {
mealy reachable_submachine(mealy&& in, state start) {
using state_out = state;
state_out max_state = 0;
map<state, state_out> new_state;
......
......@@ -4,4 +4,4 @@
struct mealy;
mealy reachable_submachine(const mealy& in, std::uint16_t start);
mealy reachable_submachine( mealy&& in, std::uint16_t start);
......@@ -83,7 +83,7 @@ mealy read_mealy_from_dot(std::istream & in, translation & t, bool check){
while(getline(in, line)){
const auto npos = std::string::npos;
if(line.find("}") != string::npos) break;
if(line.find('}') != string::npos) break;
// parse states
const auto arrow_pos = line.find("->");
......@@ -138,14 +138,14 @@ mealy read_mealy_from_dot(const string & filename, translation & t, bool check){
std::pair<mealy, translation> read_mealy_from_dot(istream & in, bool check){
translation t;
const auto m = read_mealy_from_dot(in, t, check);
auto m = read_mealy_from_dot(in, t, check);
return std::make_pair(move(m), move(t));
}
std::pair<mealy, translation> read_mealy_from_dot(const string & filename, bool check){
translation t;
const auto m = read_mealy_from_dot(filename, t, check);
auto m = read_mealy_from_dot(filename, t, check);
return std::make_pair(move(m), move(t));
}
......
......@@ -48,7 +48,6 @@ struct reverse_translation{
*/
/// \brief inverts the input_indices and output_indices maps
std::vector<std::string> create_reverse_map(const std::unordered_map<std::string, input> & indices);
std::vector<std::string> create_reverse_map(const std::unordered_map<std::string, output> & indices);
std::vector<std::vector<std::string>> create_reverse_map(const std::unordered_map<std::string, size_t> & indices,size_t size);
......
......@@ -44,7 +44,7 @@ std::ostream& rst_to_stream(readable_splitting_tree & tree, std::ostream & outpu
for(int i =0; i<tree.children.size(); i++)
{
output <<indentations << "seperator target: ";
if(reverse_valid_map.size()<1)
if(reverse_valid_map.empty())
output << "all states\n";
else
output << "{" << join(reverse_valid_map[i].begin(),reverse_valid_map[i].end(),",","}") << "\n";
......
......@@ -15,7 +15,7 @@ struct readable_splitting_tree {
: states(state_amount), depth(depth_value) {}
/// \brief constructor used to initialize the list of children with empty readable splitting trees.
readable_splitting_tree() {}
readable_splitting_tree() = default;
std::vector<std::string> states;
std::vector<std::vector<readable_splitting_tree>> children;
......
......@@ -4,10 +4,10 @@
#include "separating_family.hpp"
#include "vector_printing.hpp"
#include <unordered_map>
#include <list>
#include <algorithm>
#include <cassert>
#include <types.hpp>
std::ostream &separating_set_to_stream(std::ostream &s, const separating_set &set, const size_t indent_amount,
......@@ -43,8 +43,8 @@ void update_CI_mapping(std::unordered_map<state, std::vector<state>> &CI_mapping
const mealy &specification, const word &separator)
{
auto it = CI_mapping.begin();
const word::const_iterator start = separator.begin();
const word::const_iterator end = separator.end();
const auto start = separator.begin();
const auto end = separator.end();
//updating the CI list involves changing the keys of values, and merging certain values together under a single key.
//this is hard to do in-place, so we use this buffer map to hold the output and then switch it with the CI_mapping at the end.
......@@ -61,7 +61,7 @@ void update_CI_mapping(std::unordered_map<state, std::vector<state>> &CI_mapping
} else
{
std::vector<state> &possible_existing_value = ret[result.to];
if (possible_existing_value.size() == 0)
if (possible_existing_value.empty())
ret[result.to] = it->second;
else if (possible_existing_value.size() > it->second.size())
possible_existing_value.insert(possible_existing_value.end(), it->second.begin(), it->second.end());
......@@ -104,7 +104,7 @@ separating_family create_separating_family(const splitting_tree &tree, const mea
return states[state];
}, target);
const word separator = oboom.get_separator(target);
const word & separator = oboom.get_separator(target);
sep_set.back().insert(sep_set.back().end(), separator.begin(), separator.end());
mealy::edge target_result = apply(specification, target, separator.begin(), separator.end());
target = target_result.to;
......@@ -121,7 +121,7 @@ separating_family create_separating_family(const splitting_tree &tree, const mea
{
CI_mapping[s] = {s};
}
sep_set.push_back(word(0));
sep_set.emplace_back();
target = global_target;
}
......@@ -146,7 +146,8 @@ bool test_separating_family(const separating_family &family, const mealy &specif
auto CI_it = CI_list.begin();
for (state i = 0; i < family.size(); i++)
{
(*CI_it) = {i,i};
(*CI_it).first = i;
(*CI_it).second = i;
CI_it++;
}
for (const word &word : family[s])
......
......@@ -24,7 +24,7 @@ separating_family create_separating_family(const splitting_tree &tree, const mea
std::ostream & separating_family_to_stream(std::ostream & s, const separating_family & family,const std::vector<std::string> & inputs, const std::vector<std::string> &states);
//outputs a separating set to an ostream.
std::ostream & separating_set_to_stream(std::ostream & s, const separating_set & set,const size_t indent_amount, const std::vector<std::string> & inputs);
std::ostream & separating_set_to_stream(std::ostream & s, const separating_set & set, size_t indent_amount, const std::vector<std::string> & inputs);
//returns true if family truly behaves as a separating family.
//so for every separating set in the family,
......
......@@ -4,13 +4,12 @@
#include <algorithm>
#include <cassert>
#include <functional>
#include <numeric>
#include <queue>
#include <random>
#include <utility>
#include <unordered_set>
#include <tuple>
#include <iostream>
#include <types.hpp>
using namespace std;
......@@ -44,15 +43,6 @@ struct work_set
bool split_on_output;
};
//fills a unordered set to the point where it contains at least all the possible states up to amount.
void fill_set(unordered_set<state> &set, size_t amount)
{
set.reserve(amount-1);
for (size_t i = 0; i < amount; ++i)
{
set.emplace(i);
}
}
//removes every element in update from original. returns true if any elements were removed.
bool update_valid_set(unordered_set<state> &original, const unordered_set<state> &update)
......@@ -104,7 +94,7 @@ void add_push_new_block(deque<work_set> &work_list, list<list<state>> const &new
{
//reduce valid list to those states that are actually relevant.
unordered_set<state> new_valid_list;
if (valid_list.size() > 0)
if (!valid_list.empty())
{
for (state s : c.states)
{
......@@ -147,16 +137,9 @@ void add_push_new_block(deque<work_set> &work_list, list<list<state>> const &new
}
}
//todo: haal dit weg zodra bug gefixed is.
if(!boom.states.size() == accumulate(begin(boom.children.back()), end(boom.children.back()), 0ul,
[](size_t l, const splitting_tree &r)
{
return l + r.states.size();
}))
throw runtime_error("assert failed");
assert(boom.children.size()==boom.separators.size());
if(boom.children.size()>1)
assert(boom.valid_map.size()>0);
assert(!boom.valid_map.empty());
assert(boom.states.size() == accumulate(begin(boom.children.back()), end(boom.children.back()), 0ul,
[](size_t l, const splitting_tree &r)
{
......@@ -237,7 +220,7 @@ splitting_tree create_splitting_tree(const mealy &g)
//used when selecting a separator from multiple options.
//The preference is the one which is valid for valid_target, if it exists.
state valid_target;
if (valid_set.size() > 0)
if (!valid_set.empty())
valid_target = *valid_set.begin();
else
valid_target = boom.states.front();
......@@ -246,10 +229,6 @@ splitting_tree create_splitting_tree(const mealy &g)
if (boom.states.size() == 1) continue;
//todo: debug code. verwijder dit zodra bug gefixed is.
if(boom.states.size()==2 &&(boom.states[0]==2705 || boom.states[0]==2959))
bool test = true;
//possible progress is splitted into tree different categories: on output, on state and force_progress.
//for each loop iteration, only one of these three categories is executed. the choise depends on the value of some flags.
......@@ -275,7 +254,7 @@ splitting_tree create_splitting_tree(const mealy &g)
if (!is_valid(new_blocks, symbol, valid_set)) continue;
// a succesful split, update partition and add the children
boom.separators.push_back({symbol});
boom.separators.emplace_back(word(1,symbol));
add_push_new_block(work_list,new_blocks, boom, valid_set, false);
goto has_split;
......@@ -293,9 +272,9 @@ splitting_tree create_splitting_tree(const mealy &g)
//the forced progress might open new options, for which we check first before we force progress again.
force_progress = false;
assert(valid_set.empty()|| [&valid_set](splitting_tree & boom)
assert(valid_set.empty()|| [&valid_set](const splitting_tree & boom)
{
for (state s : valid_set)
for (const state s : valid_set)
{
if (std::find(boom.states.begin(), boom.states.end(), s) != boom.states.end())
{
......@@ -371,7 +350,7 @@ splitting_tree create_splitting_tree(const mealy &g)
assert(new_blocks.size()>1);
// a succesful split, save the required information for later.
splits.emplace_back(vector(1,symbol),move(new_blocks),move(new_valid_set));
splits.emplace_back(word(1,symbol),move(new_blocks),move(new_valid_set));
if(updated_separator)
{
best_split_index = splits.size()-1;
......@@ -473,6 +452,7 @@ splitting_tree create_splitting_tree(const mealy &g)
{
//if we get here then the algorithm has failed.
//we return the root anyway so we can inspect the partial solution in the output file.
cout << "warning, algorithm failed. returning partial results\n";
return root;
}
goto has_no_split;
......@@ -492,7 +472,7 @@ splitting_tree create_splitting_tree(const mealy &g)
for(auto split : splits)
{
boom.separators.push_back(get<0>(split));
boom.separators.push_back(move(get<0>(split)));
add_push_new_block(work_list,get<1>(split),boom,get<2>(split),true);
}
......
......@@ -17,11 +17,11 @@ struct splitting_tree {
std::unordered_map<state,size_t> valid_map;
const std::vector<splitting_tree> & get_children(state s) const {
if(children.size()<1)
if(children.empty())
throw std::runtime_error("get_children called when there were no children");
else if(children.size()==1)
return children.front();
else if(valid_map.size()<1 ||valid_map.count(s)<1)
else if(valid_map.empty()||valid_map.count(s)<1)
throw std::runtime_error("valid map does not contain required information");
else
return children[valid_map.at(s)];
......@@ -31,7 +31,7 @@ struct splitting_tree {
//otherwise behaves exactly the same as get_children.
//this behaviour is required for the lca_impl, but might mask errors if used elsewere.
const std::vector<splitting_tree> & get_children_reliably(state s) const {
if(children.size()<1)
if(children.empty())
throw std::runtime_error("get_children called when there were no children");
else if(valid_map.count(s)<1)
return children.front();
......@@ -40,11 +40,11 @@ struct splitting_tree {
}
const word & get_separator(state s) const {
if (children.size() < 1)
if (children.empty())
throw std::runtime_error("get_separator called when there were no separators");
else if(children.size()==1)
return separators.front();
else if (valid_map.size() < 1 || valid_map.count(s) < 1)
else if (valid_map.empty() || valid_map.count(s) < 1)
throw std::runtime_error("valid map does not contain required information");
else
return separators[valid_map.at(s)];
......@@ -87,7 +87,6 @@ size_t lca_impl(splitting_tree const & node, Fun && f, Store && store, state val
return count;
}
throw std::logic_error("unreachable code");
}
/// \brief Find the lowest common ancestor of elements on which \p f returns true.
......
......@@ -14,8 +14,8 @@ using word = std::vector<input>;
template <typename T>
std::vector<T> concat(std::vector<T> const & l, std::vector<T> const & r){
std::vector<T> ret(l.size() + r.size());
auto it = copy(begin(l), end(l), begin(ret));
copy(begin(r), end(r), it);
auto it = std::copy(begin(l), end(l), begin(ret));
std::copy(begin(r), end(r), it);
return ret;
}
......
#pragma once
#include <string.h>
#include <stdio.h>
#include <cstring>
#include <cstdio>
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
......@@ -49,7 +49,7 @@ int
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
optarg = nullptr;
if (!*place)
++optind;
}
......
......@@ -36,7 +36,7 @@ extern "C" {
using namespace std;
static const char USAGE[] =
R"(Generate or stream a test suite for a given FSM.
R"(Generate or stream a test suite for a given FSM.
Usage:
main [options]
......@@ -44,162 +44,182 @@ static const char USAGE[] =
Options:
-h Show this screen
-v Show version
-a treat the input file name as an absolute path instead of a relative one.
-k <num> Number of extra states to check for (minus 1). currently not supported
-x <seed> 32 bits seeds for deterministic execution (0 is not valid). currently not supported
-f <filename> Input filename ('-' or don't specify for default example). path should be relative to examples directory
-o <filename> Output filename ('-' or don't specify for default output file). path should be relative to outputs directory
)";
static const string output_directory = "../outputs/";
static const string input_directory = "../examples/";
const string output_directory = "../outputs/";
string input_directory = "../examples/";
struct main_options {
bool help = false;
bool version = false;
struct main_options
{
bool help = false;
bool version = false;
unsigned long k_max = 1; // 3 means 2 extra states. currently not supported
unsigned long seed = 0; // 0 for unset/noise. currently not supported
unsigned long k_max = 1; // 3 means 2 extra states. currently not supported
unsigned long seed = 0; // 0 for unset/noise. currently not supported
//"coffe_machine.dot";
//"lee_yannakakis_difficult.dot";
//"lee_yannakakis_distinguishable.dot";
string input_filename = input_directory+"esm-manual-controller.dot";
string output_filename = "";
//"coffe_machine.dot";
//"lee_yannakakis_difficult.dot";
//"lee_yannakakis_distinguishable.dot";
//"esm-manual-controller.dot";
string input_filename = input_directory + "lee_yannakakis_difficult.dot";
string output_filename = "";
};
main_options parse_options(int argc, char ** argv) {
main_options opts;
try {
int c;
while ((c = getopt(argc, argv, "hvk:x:f:o:")) != -1) {
switch (c) {
case 'h': // show help message
opts.help = true;
break;
case 'v': // show version
opts.version = true;
break;
case 'k': // select extra states / k-value
opts.k_max = stoul(optarg);
break;
case 'x': // seed
opts.seed = stoul(optarg);
break;
case 'f': // input filename
opts.input_filename = input_directory + optarg;
break;
case 'o': // output filename
opts.output_filename = output_directory + optarg;
break;
case ':': // some option without argument
throw runtime_error(string("No argument given to option -") + char(optopt));
case '?': // all unrecognised things
throw runtime_error(string("Unrecognised option -") + char(optopt));
}
}
} catch (exception & e) {
cerr << e.what() << endl;
cerr << "Could not parse command line options." << endl;
cerr << "Please use -h to see the available options." << endl;
exit(2);
}
//generate outputfile name based on inputfile name.
if(opts.output_filename == "")
{
size_t start = opts.input_filename.find_last_of('/');
if(start == std::string::npos)
start = opts.input_filename.find_last_of('\\');
size_t end = opts.input_filename.find_last_of('.');
if(start >=end || end == std::string::npos)
opts.output_filename = output_directory + "default_output.txt";
else
opts.output_filename = output_directory + opts.input_filename.substr(start,end-start) + "_output.txt";
}
return opts;
main_options parse_options(int argc, char **argv)
{
main_options opts;
try
{
int c;
while ((c = getopt(argc, argv, "hvak:x:f:o:")) != -1)
{
switch (c)
{
case 'h': // show help message
opts.help = true;
break;
case 'v': // show version
opts.version = true;
break;
case 'a': //use absolute input paths
input_directory = "";
break;
case 'k': // select extra states / k-value
opts.k_max = stoul(optarg);
break;
case 'x': // seed
opts.seed = stoul(optarg);
break;
case 'f': // input filename
opts.input_filename = input_directory + optarg;
break;
case 'o': // output filename
opts.output_filename = output_directory + optarg;
break;
case ':': // some option without argument
throw runtime_error(string("No argument given to option -") + char(optopt));
case '?': // all unrecognised things
default: //should never happen but included for completeness sake.
throw runtime_error(string("Unrecognised option -") + char(optopt));
}
}
} catch (exception &e)
{
cerr << e.what() << endl;
cerr << "Could not parse command line options." << endl;
cerr << "Please use -h to see the available options." << endl;
exit(2);
}
//generate outputfile name based on inputfile name.
if (opts.output_filename.empty())
{
size_t start = opts.input_filename.find_last_of('/');
if (start == std::string::npos)
start = opts.input_filename.find_last_of('\\');
size_t end = opts.input_filename.find_last_of('.');
if (start >= end || end == std::string::npos)
opts.output_filename = output_directory + "default_output.txt";
else
opts.output_filename = output_directory + opts.input_filename.substr(start, end - start) + "_output.txt";
}
return opts;
}
int main(int argc, char * argv[]){
/*
* First we parse the command line options.
* We quit when asked for help or version
*/
const auto args = parse_options(argc, argv);
if (args.help) {
cout << USAGE << endl;
exit(0);
}
if (args.version) {
cout << "Version 1 (October 2018)" << endl;
exit(0);
}
/*
* Then all the setup is done. Parsing the automaton,
* constructing all types of sequences needed for the
* test suite.
*/
const auto machine_and_translation = [&] {
const auto & filename = args.input_filename;
if (filename == "" || filename == "-") {
return read_mealy_from_dot(cin);
}
if (filename.find(".txt") != string::npos) {
const auto m = read_mealy_from_txt(filename);
const auto t = create_translation_for_mealy(m);
return make_pair(move(m), move(t));
} else if (filename.find(".dot") != string::npos) {
return read_mealy_from_dot(filename);
}
clog << "warning: unrecognized file format, assuming .dot\n";
return read_mealy_from_dot(filename);
}();
const auto & machine = reachable_submachine(move(machine_and_translation.first), 0U);
const auto & translation = machine_and_translation.second;
int main(int argc, char *argv[])
{
/*
* First we parse the command line options.
* We quit when asked for help or version
*/
const auto args = parse_options(argc, argv);
if (args.help)
{
cout << USAGE << endl;
exit(0);
}
if (args.version)
{
cout << "Version 1 (October 2018)" << endl;
exit(0);
}
/*
* Then all the setup is done. Parsing the automaton,
* constructing all types of sequences needed for the
* test suite.
*/
auto machine_and_translation = [&]
{
const auto &filename = args.input_filename;
if (filename.empty() || filename == "-")
{
return read_mealy_from_dot(cin);
}
if (filename.find(".txt") != string::npos)
{