You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
15 KiB

  1. #include "jani.h"
  2. #include <storm/storage/jani/Model.h>
  3. #include <storm/storage/jani/JSONExporter.h>
  4. #include <storm/storage/expressions/ExpressionManager.h>
  5. #include <storm/logic/RewardAccumulationEliminationVisitor.h>
  6. #include <storm/storage/jani/traverser/InformationCollector.h>
  7. #include <storm/storage/jani/JaniLocationExpander.h>
  8. #include <storm/storage/jani/JaniScopeChanger.h>
  9. #include "src/helpers.h"
  10. using namespace storm::jani;
  11. std::string janiToString(Model const& m) {
  12. std::stringstream str;
  13. JsonExporter::toStream(m, {}, str);
  14. return str.str();
  15. }
  16. void define_jani(py::module& m) {
  17. py::class_<Model, std::shared_ptr<Model>> md(m, "JaniModel", "A Jani Model");
  18. md.def(py::init<Model>(), "other_model"_a)
  19. .def_property_readonly("name", &Model::getName, "model name")
  20. .def_property_readonly("model_type", &storm::jani::Model::getModelType, "Model type")
  21. .def("set_model_type", &Model::setModelType, "Sets (only) the model type")
  22. .def_property_readonly("automata", [](const Model& model) -> auto& {return model.getAutomata();}, "get automata")
  23. .def_property_readonly("global_variables", [](const Model& model) -> auto& {return model.getGlobalVariables();})
  24. .def_property_readonly("constants", [](const Model& model) -> auto& {return model.getConstants();}, "get constants")
  25. .def("get_constant", &Model::getConstant, "name"_a, "get constant by name")
  26. .def("restrict_edges", &Model::restrictEdges, "restrict model to edges given by set", py::arg("edge_set"))
  27. .def_property_readonly("expression_manager", &Model::getExpressionManager, "get expression manager", pybind11::return_value_policy::reference_internal)
  28. .def_property_readonly("has_undefined_constants", &Model::hasUndefinedConstants, "Flag if program has undefined constants")
  29. .def_property_readonly("undefined_constants_are_graph_preserving", &Model::undefinedConstantsAreGraphPreserving, "Flag if the undefined constants do not change the graph structure")
  30. .def("__str__", &janiToString)
  31. .def_property("initial_states_restriction", &Model::getInitialStatesRestriction, &Model::setInitialStatesRestriction, "initial states restriction")
  32. .def("add_constant", &Model::addConstant, "adds constant to model", py::arg("constant"))
  33. .def("define_constants", &Model::defineUndefinedConstants, "define constants with a mapping from the corresponding expression variables to expressions", py::arg("map"))
  34. .def("substitute_constants", &Model::substituteConstants, "substitute constants")
  35. .def("remove_constant", &Model::removeConstant, "remove a constant. Make sure the constant does not appear in the model.", "constant_name"_a)
  36. .def("get_automaton", [](Model const& model, std::string const& name) {return model.getAutomaton(name);}, "name"_a)
  37. .def("get_automaton_index", &Model::getAutomatonIndex, "name"_a, "get index for automaton name")
  38. .def("add_automaton", &Model::addAutomaton, "automaton"_a, "add an automaton (with a unique name)")
  39. .def("set_standard_system_composition", &Model::setStandardSystemComposition, "sets the composition to the standard composition")
  40. .def("replace_automaton", &Model::replaceAutomaton, "index"_a, "new_automaton"_a, "replace automaton at index")
  41. .def("check_valid", &Model::checkValid, "Some basic checks to ensure validity")
  42. .def("substitute_functions", [](Model& model) {model.substituteFunctions();}, "substitute functions")
  43. .def_static("encode_automaton_and_edge_index", &Model::encodeAutomatonAndEdgeIndices, "get edge/automaton-index")
  44. .def_static("decode_automaton_and_edge_index", &Model::decodeAutomatonAndEdgeIndices, "get edge and automaton from edge/automaton index")
  45. .def("make_standard_compliant", &Model::makeStandardJaniCompliant, "make standard JANI compliant")
  46. .def("has_standard_composition", &Model::hasStandardComposition, "is the composition the standard composition")
  47. .def("flatten_composition", &Model::flattenComposition, py::arg("smt_solver_factory")=std::make_shared<storm::utility::solver::SmtSolverFactory>())
  48. .def("finalize", &Model::finalize,"finalizes the model. After this action, be careful changing the data structure.")
  49. .def("to_dot", [](Model& model) {std::stringstream ss; model.writeDotToStream(ss); return ss.str(); })
  50. ;
  51. py::class_<Automaton, std::shared_ptr<Automaton>> automaton(m, "JaniAutomaton", "A Jani Automation");
  52. automaton.def(py::init<std::string, storm::expressions::Variable>())
  53. .def_property_readonly("edges",[](const Automaton& a) -> auto& {
  54. return a.getEdges();
  55. }, "get edges")
  56. .def_property_readonly("name", &Automaton::getName)
  57. .def_property_readonly("location_variable", &Automaton::getLocationExpressionVariable)
  58. .def_property_readonly("variables", [](Automaton& aut) -> VariableSet& {return aut.getVariables();}, py::return_value_policy::reference_internal)
  59. .def_property_readonly("locations", [](Automaton& aut) -> auto& {return aut.getLocations();})
  60. .def("add_location", &Automaton::addLocation, "location"_a, "adds a new location, returns the index")
  61. .def("add_initial_location", [](Automaton& aut, uint64_t index) { aut.addInitialLocation(index); }, "index"_a)
  62. .def_property_readonly("initial_location_indices", &Automaton::getInitialLocationIndices)
  63. .def_property("initial_states_restriction", [](Automaton& aut) { aut.getInitialStatesExpression(); }, &Automaton::setInitialStatesRestriction, "initial state restriction")
  64. .def("add_edge", &Automaton::addEdge, "edge"_a)
  65. .def("get_location_index", &Automaton::getLocationIndex, "name"_a)
  66. ;
  67. py::class_<Edge, std::shared_ptr<Edge>> edge(m, "JaniEdge", "A Jani Edge");
  68. edge.def(py::init<uint64_t, uint64_t, boost::optional<storm::expressions::Expression>, std::shared_ptr<TemplateEdge>, std::vector<std::pair<uint64_t, storm::expressions::Expression>>>(),
  69. "source_location_index"_a, "action_index"_a, "rate"_a, "template_edge"_a, "destinations_with_probabilities"_a)
  70. .def_property_readonly("source_location_index", &Edge::getSourceLocationIndex, "index for source location")
  71. .def_property_readonly("destinations", [](Edge const& e) -> auto& {
  72. return e.getDestinations();
  73. }, "edge destinations")
  74. .def_property_readonly("action_index", &Edge::getActionIndex, "action index")
  75. .def_property_readonly("template_edge", &Edge::getTemplateEdge, "template edge")
  76. .def_property_readonly("rate", &Edge::getOptionalRate, "edge rate")
  77. .def_property_readonly("nr_destinations", &Edge::getNumberOfDestinations, "nr edge destinations")
  78. .def_property_readonly("guard", &Edge::getGuard, "edge guard")
  79. .def_property("color", &Edge::getColor, &Edge::setColor, "color for the edge")
  80. .def("substitute", &Edge::substitute, py::arg("mapping"))
  81. .def("has_silent_action", &Edge::hasSilentAction, "Is the edge labelled with the silent action")
  82. ;
  83. py::class_<TemplateEdge, std::shared_ptr<TemplateEdge>> templateEdge(m, "JaniTemplateEdge", "Template edge, internal data structure for edges");
  84. templateEdge.def(py::init<storm::expressions::Expression>())
  85. .def_property_readonly("assignments", [](TemplateEdge& te) -> auto& { return te.getAssignments(); })
  86. .def_property("guard", &TemplateEdge::getGuard, &TemplateEdge::setGuard)
  87. .def_property_readonly("destinations",[](TemplateEdge& te) -> auto& { return te.getDestinations(); })
  88. .def("add_destination", &TemplateEdge::addDestination)
  89. ;
  90. py::class_<EdgeDestination, std::shared_ptr<EdgeDestination>> edgeDestination(m, "JaniEdgeDestination", "Destination in Jani");
  91. edgeDestination.def_property_readonly("target_location_index", &EdgeDestination::getLocationIndex)
  92. .def_property_readonly("probability", &EdgeDestination::getProbability)
  93. .def_property_readonly("assignments", &EdgeDestination::getOrderedAssignments)
  94. ;
  95. py::class_<TemplateEdgeDestination, std::shared_ptr<TemplateEdgeDestination>> templateEdgeDestination(m, "JaniTemplateEdgeDestination", "Template edge destination, internal data structure for edge destinations");
  96. templateEdgeDestination.def(py::init<OrderedAssignments>(), "ordered_assignments"_a)
  97. .def_property_readonly("assignments", [](TemplateEdgeDestination& ted) -> auto& {return ted.getOrderedAssignments();});
  98. py::class_<OrderedAssignments, std::shared_ptr<OrderedAssignments>> orderedAssignments(m, "JaniOrderedAssignments", "Set of assignments");
  99. orderedAssignments.def("__iter__", [](OrderedAssignments &v) {
  100. return py::make_iterator(v.begin(), v.end());
  101. }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
  102. .def(py::init<std::vector<Assignment> const&>(), "assignments")
  103. .def("__str__", &streamToString<OrderedAssignments>)
  104. .def("clone", &OrderedAssignments::clone, "clone assignments (performs a deep copy)")
  105. .def("substitute", &OrderedAssignments::substitute, "substitute in rhs according to given substitution map", "substitution_map"_a)
  106. .def("add", [](OrderedAssignments& oa, Assignment const& newAssignment, bool addToExisting) {return oa.add(newAssignment, addToExisting); }, "new_assignment"_a, "add_to_existing"_a = false)
  107. ;
  108. py::class_<Assignment, std::shared_ptr<Assignment>> assignment(m, "JaniAssignment", "Jani Assignment");
  109. assignment.def(py::init<Variable const&,storm::expressions::Expression const&,int64_t>(), "lhs"_a, "rhs"_a, "lvl"_a = 0)
  110. .def("__str__", &streamToString<Assignment>)
  111. .def_property("expression", &Assignment::getAssignedExpression, &Assignment::setAssignedExpression)
  112. .def_property_readonly("variable", &Assignment::getVariable, "variable that is assigned to, if any")
  113. ;
  114. py::class_<Location, std::shared_ptr<Location>> location(m, "JaniLocation", "A Location in JANI");
  115. location.def(py::init<std::string const&, OrderedAssignments const&>(), "name"_a, "assignments"_a)
  116. .def_property_readonly("name", &Location::getName, "name of the location")
  117. .def_property_readonly("assignments", [](Location& loc) {loc.getAssignments();}, "location assignments")
  118. ;
  119. py::class_<VariableSet, std::shared_ptr<VariableSet>> variableSet(m, "JaniVariableSet", "Jani Set of Variables");
  120. variableSet.def(py::init<>())
  121. .def("__iter__", [](VariableSet &v) {
  122. return py::make_iterator(v.begin(), v.end());
  123. }, py::keep_alive<0, 1>())
  124. .def("add_variable", [](VariableSet& vs, Variable& v) -> void { vs.addVariable(v); })
  125. .def("add_bounded_integer_variable", [](VariableSet& vs, BoundedIntegerVariable& v) -> auto& { return vs.addVariable(v); /*return vs.getVariable(v.getExpressionVariable());*/ }, py::return_value_policy::reference_internal, "variable"_a)
  126. .def("empty", &VariableSet::empty, "is there a variable in the set?")
  127. .def("get_variable_by_name", [](VariableSet& v, std::string const& name) -> auto& { return v.getVariable(name);})
  128. .def("get_variable_by_expr_variable", [](VariableSet& v, storm::expressions::Variable const& var) -> auto& { return v.getVariable(var);})
  129. .def("erase_variable", &VariableSet::eraseVariable, "variable")
  130. ;
  131. py::class_<Variable, std::shared_ptr<Variable>> variable(m, "JaniVariable", "A Variable in JANI");
  132. variable.def_property_readonly("name", &Variable::getName, "name of constant")
  133. .def_property_readonly("expression_variable", &Variable::getExpressionVariable, "expression variable for this variable")
  134. .def_property_readonly("init_expression", &Variable::getInitExpression);
  135. py::class_<BoundedIntegerVariable, std::shared_ptr<BoundedIntegerVariable>> bivariable(m, "JaniBoundedIntegerVariable", "A Bounded Integer", variable);
  136. bivariable.def(py::init<std::string, storm::expressions::Variable, storm::expressions::Expression, storm::expressions::Expression, storm::expressions::Expression>(),
  137. "name"_a, "expression_variable"_a, "init_value"_a, "lower_bound"_a, "upper_bound"_a)
  138. .def(py::init<std::string, storm::expressions::Variable, storm::expressions::Expression, storm::expressions::Expression>(),
  139. "name"_a, "expression_variable"_a, "lower_bound"_a, "upper_bound"_a)
  140. .def_property_readonly("lower_bound", &BoundedIntegerVariable::getLowerBound)
  141. .def_property_readonly("upper_bound", &BoundedIntegerVariable::getUpperBound)
  142. ;
  143. py::class_<Constant, std::shared_ptr<Constant>> constant(m, "JaniConstant", "A Constant in JANI");
  144. constant.def(py::init<std::string, storm::expressions::Variable>())
  145. .def_property_readonly("defined", &Constant::isDefined, "is constant defined by some expression")
  146. .def_property_readonly("name", &Constant::getName, "name of constant")
  147. .def_property_readonly("type", &Constant::getType, "type of constant")
  148. .def_property_readonly("expression_variable", &Constant::getExpressionVariable, "expression variable for this constant")
  149. ;
  150. m.def("eliminate_reward_accumulations", [](const Model& model, std::vector<Property>& properties) {
  151. storm::logic::RewardAccumulationEliminationVisitor v(model);
  152. v.eliminateRewardAccumulations(properties);
  153. return properties;
  154. }, "Eliminate reward accumulations", py::arg("model"), py::arg("properties"));
  155. py::class_<InformationObject> informationObject(m, "JaniInformationObject", "An object holding information about a JANI model");
  156. informationObject.def_readwrite("model_type", &InformationObject::modelType)
  157. .def_readwrite("nr_automata", &InformationObject::nrAutomata)
  158. .def_readwrite("nr_edges", &InformationObject::nrEdges)
  159. .def_readwrite("nr_variables", &InformationObject::nrVariables)
  160. .def_readwrite("state_domain_size", &InformationObject::stateDomainSize)
  161. .def_readwrite("avg_var_domain_size", &InformationObject::avgVarDomainSize);
  162. m.def("collect_information", [](const Model& model) {return storm::jani::collectModelInformation(model);});
  163. }
  164. void define_jani_transformers(py::module& m) {
  165. py::class_<JaniLocationExpander>(m, "JaniLocationExpander", "A transformer for Jani expanding variables into locations")
  166. .def(py::init<Model const&>(), py::arg("model"))
  167. .def("transform", &JaniLocationExpander::transform, py::arg("automaton_name"), py::arg("variable_name"))
  168. .def("get_result", &JaniLocationExpander::getResult);
  169. py::class_<JaniScopeChanger>(m, "JaniScopeChanger", "A transformer for Jani changing variables from local to global and vice versa")
  170. .def(py::init<>())
  171. .def("make_variables_local", [](JaniScopeChanger const& sc, Model const& model , std::vector<Property> const& props = {}) { Model newModel(model); sc.makeVariablesLocal(newModel, props); return newModel;}, py::arg("model"), py::arg("properties") = std::vector<Property>());
  172. }