diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5232ae8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + "files.associations": { + "sstream": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ca1571..0392819 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,26 @@ -include(util/CMakeLists.txt) - -set(CMAKE_CXX_STANDARD 20) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") -add_definitions(-DLOG_DEBUG) - cmake_minimum_required(VERSION 3.0...3.22) - -set(CMAKE_BUILD_TYPE Debug) - project( Minigrid2PRISM VERSION 0.1 LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 20) + +include(util/CMakeLists.txt) +include(FetchContent) -add_executable(main - ${SRCS} - main.cpp - ) +FetchContent_Declare( + yaml-cpp + GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git + GIT_TAG master + OVERRIDE_FIND_PACKAGE +) +FetchContent_GetProperties(yaml-cpp) +if(NOT yaml-cpp_POPULATED) + message(STATUS "Fetching yaml-cpp...") + FetchContent_Populate(yaml-cpp) + add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR}) +endif() +FetchContent_MakeAvailable(yaml-cpp) -target_link_libraries(main pthread) +add_executable(main ${SRCS} main.cpp) +target_link_libraries(main pthread yaml-cpp::yaml-cpp) diff --git a/main.cpp b/main.cpp index 58de07f..be33399 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,14 @@ #include "util/OptionParser.h" #include "util/MinigridGrammar.h" #include "util/Grid.h" +#include "util/ConfigYaml.h" #include #include #include #include + std::vector parseCommaSeparatedString(std::string const& str) { std::vector result; std::stringstream stream(str); @@ -19,6 +21,7 @@ std::vector parseCommaSeparatedString(std::string const& str) { return result; } + struct printer { typedef boost::spirit::utf8_string string; @@ -54,6 +57,9 @@ int main(int argc, char* argv[]) { auto enforceOneWays = optionParser.add("f", "force-oneways", "Enforce encoding of oneways. This entails that slippery tiles do not allow turning and have prob 1 to shift the agent by one and makes turning impossible if in a one tile wide section of the grid."); + auto configFilename = optionParser.add, popl::Attribute::optional>("c", "config-file", "Filename of the predicate configuration file."); + + try { optionParser.parse(argc, argv); @@ -100,32 +106,36 @@ int main(int argc, char* argv[]) { std::fstream file {outputFilename->value(0), file.trunc | file.out}; std::fstream infile {inputFilename->value(0), infile.in}; - std::string line, content, background, rewards; + std::string line, content, background, rewards, properties; std::cout << "\n"; bool parsingBackground = false; bool parsingStateRewards = false; + bool parsingEnvironmentProperties = false; while (std::getline(infile, line) && !line.empty()) { if(line.at(0) == '-' && line.at(line.size() - 1) == '-' && parsingBackground) { parsingStateRewards = true; parsingBackground = false; continue; + } else if (line.at(0) == '-' && line.at(line.size() - 1 ) == '-' && parsingStateRewards) { + parsingStateRewards = false; + parsingEnvironmentProperties = true; + continue; } else if(line.at(0) == '-' && line.at(line.size() - 1) == '-') { parsingBackground = true; continue; } - if(!parsingBackground && !parsingStateRewards) { - std::cout << "Reading :\t" << line << "\n"; + if(!parsingBackground && !parsingStateRewards && !parsingEnvironmentProperties) { content += line + "\n"; } else if (parsingBackground) { - std::cout << "Background:\t" << line << "\n"; background += line + "\n"; } else if(parsingStateRewards) { rewards += line + "\n"; + } else if (parsingEnvironmentProperties) { + properties += line + "\n"; } } std::cout << "\n"; - pos_iterator_t contentFirst(content.begin()); pos_iterator_t contentIter = contentFirst; pos_iterator_t contentLast(content.end()); @@ -137,12 +147,20 @@ int main(int argc, char* argv[]) { cells contentCells; cells backgroundCells; + std::vector configurations; std::map stateRewards; + float faultyProbability = 0.0; + float probIntended = 0.9; + try { bool ok = phrase_parse(contentIter, contentLast, contentParser, qi::space, contentCells); // TODO if(background is not empty) { ok &= phrase_parse(backgroundIter, backgroundLast, backgroundParser, qi::space, backgroundCells); // TODO } + if (configFilename->is_set()) { + YamlConfigParser parser(configFilename->value(0)); + configurations = parser.parseConfiguration(); + } boost::escaped_list_separator seps('\\', ';', '\n'); Tokenizer csvParser(rewards, seps); @@ -152,10 +170,27 @@ int main(int argc, char* argv[]) { float reward = std::stof(*(++iter)); stateRewards[std::make_pair(x,y)] = reward; } + if (!properties.empty()) { + auto faultProbabilityIdentifier = std::string("FaultProbability:"); + auto start_pos = properties.find(faultProbabilityIdentifier); + + + if (start_pos != std::string::npos) { + auto end_pos = properties.find('\n', start_pos); + auto value = properties.substr(start_pos + faultProbabilityIdentifier.length(), end_pos - start_pos - faultProbabilityIdentifier.length()); + faultyProbability = std::stod(value); + } + } if(ok) { - Grid grid(contentCells, backgroundCells, gridOptions, stateRewards); - //grid.printToPrism(std::cout, prism::ModelType::MDP); - grid.printToPrism(file, prism::ModelType::MDP); + Grid grid(contentCells, backgroundCells, gridOptions, stateRewards, probIntended, faultyProbability); + + grid.printToPrism(std::cout, configurations , gridOptions.getModelType()); + std::stringstream ss; + // grid.printToPrism(file, configurations ,prism::ModelType::MDP); + grid.printToPrism(ss, configurations , gridOptions.getModelType()); + std::string str = ss.str(); + grid.applyOverwrites(str, configurations); + file << str; } } catch(qi::expectation_failure const& e) { std::cout << "expected: "; print_info(e.what_); diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index f5884fe..2325d92 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -2,7 +2,10 @@ list(APPEND SRCS ${CMAKE_CURRENT_LIST_DIR}/cell.cpp ${CMAKE_CURRENT_LIST_DIR}/MinigridGrammar.h ${CMAKE_CURRENT_LIST_DIR}/Grid.cpp + ${CMAKE_CURRENT_LIST_DIR}/PrismPrinter.cpp ${CMAKE_CURRENT_LIST_DIR}/PrismModulesPrinter.cpp + ${CMAKE_CURRENT_LIST_DIR}/PrismFormulaPrinter.cpp ${CMAKE_CURRENT_LIST_DIR}/popl.hpp ${CMAKE_CURRENT_LIST_DIR}/OptionParser.cpp + ${CMAKE_CURRENT_LIST_DIR}/ConfigYaml.cpp ) diff --git a/util/ConfigYaml.cpp b/util/ConfigYaml.cpp new file mode 100644 index 0000000..07c2b8e --- /dev/null +++ b/util/ConfigYaml.cpp @@ -0,0 +1,238 @@ +#include "ConfigYaml.h" +#include + +std::ostream& operator <<(std::ostream &os, const Label& label) { + os << "\"" << label.label_ << "\"" << "=" << label.text_; + return os; +} + +std::ostream& operator << (std::ostream &os, const Formula& formula) { + os << formula.formula_ << "=" << formula.content_; + return os; +} + +std::ostream& operator << (std::ostream& os, const Action& action) { + os << action.action_; + return os; +} + +std::ostream& operator << (std::ostream& os, const Constant& constant) { + os << "const " << constant.type_ << " " << constant.constant_ << " = " << constant.value_; + return os; +} + +std::ostream& operator << (std::ostream& os, const Module& module) { + os << "Module: " << module.module_ << std::endl; + for (auto& action : module.actions_) { + os << action << std::endl; + } + return os; +} + +std::string Label::createExpression() const { + if (overwrite_) { + return "label \"" + label_ + "\" = " + text_ + Configuration::overwrite_identifier_; + } + + return "label \"" + label_ + "\" = " + text_ + Configuration::configuration_identifier_; +} + +std::string Formula::createExpression() const { + if (overwrite_) { + return "formula " + formula_ + " = " + content_ + Configuration::overwrite_identifier_; + } + + return "formula " + formula_ + " = " + content_ + Configuration::configuration_identifier_; +} + +std::string Action::createExpression() const { + if (overwrite_) { + return action_ + "\t" + guard_ + "-> " + update_ + Configuration::overwrite_identifier_; + } + + return "\t" + action_ + "\t" + guard_ + "-> " + update_+ Configuration::configuration_identifier_; +} + +std::string Constant::createExpression() const { + if (overwrite_) { + return "const " + type_ + " " + constant_ + " = " + value_ + Configuration::overwrite_identifier_; + } + + return "const " + type_ + " " + constant_ + " = " + value_ + Configuration::configuration_identifier_; +} + +YAML::Node YAML::convert::encode(const Module& rhs) { + YAML::Node node; + + node.push_back(rhs.module_); + node.push_back(rhs.actions_); + + return node; +} + +bool YAML::convert::decode(const YAML::Node& node, Module& rhs) { + if (!node.Type() == NodeType::Map) { + return false; + } + rhs.actions_ = node["actions"].as>(); + rhs.module_ = node["module"].as(); + return true; +} + +YAML::Node YAML::convert::encode(const Action& rhs) { + YAML::Node node; + + node.push_back(rhs.action_); + node.push_back(rhs.guard_); + node.push_back(rhs.overwrite_); + node.push_back(rhs.update_); + + return node; +} + +bool YAML::convert::decode(const YAML::Node& node, Action& rhs) { + if (!node.Type() == NodeType::Map) { + return false; + } + + rhs.action_ = node["action"].as(); + rhs.guard_ = node["guard"].as(); + rhs.update_ = node["update"].as(); + + if (node["overwrite"]) { + rhs.overwrite_ = node["overwrite"].as(); + } + if (node["index"]) { + rhs.index_ = node["index"].as(); + } + + return true; +} + + +YAML::Node YAML::convert