diff --git a/stormpy/src/core/core.cpp b/stormpy/src/core/core.cpp index 0883f133f..bec89f54a 100644 --- a/stormpy/src/core/core.cpp +++ b/stormpy/src/core/core.cpp @@ -17,24 +17,48 @@ std::shared_ptr<storm::models::ModelBase> buildModel(storm::prism::Program const return storm::buildSymbolicModel<storm::RationalFunction>(program, std::vector<std::shared_ptr<const storm::logic::Formula>>(1,formula)).model; } +// Thin wrapper for bisimulation +template<typename ValueType> +std::shared_ptr<storm::models::sparse::Model<ValueType>> performBisimulation(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, std::shared_ptr<const storm::logic::Formula> const& formula, storm::storage::BisimulationType bisimulationType) { + return storm::performBisimulationMinimization<storm::models::sparse::Model<ValueType>>(model, formula, bisimulationType); +} + // Class holding the model checking result -/*class PmcResult { +class PmcResult { public: storm::RationalFunction resultFunction; std::unordered_set<storm::ArithConstraint<storm::RationalFunction>> constraintsWellFormed; std::unordered_set<storm::ArithConstraint<storm::RationalFunction>> constraintsGraphPreserving; + + /*storm::RationalFunction getFunc() { + return resultFunction; + }*/ + + std::string toString() { + std::stringstream stream; + stream << resultFunction << std::endl; + stream << "Well formed constraints:" << std::endl; + for (auto constraint : constraintsWellFormed) { + stream << constraint << std::endl; + } + stream << "Graph preserving constraints:" << std::endl; + for (auto constraint : constraintsGraphPreserving) { + stream << constraint << std::endl; + } + return stream.str(); + } }; // Thin wrapper for parametric state elimination std::shared_ptr<PmcResult> performStateElimination(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> model, std::shared_ptr<storm::logic::Formula> const& formula) { std::unique_ptr<storm::modelchecker::CheckResult> checkResult = storm::verifySparseModel<storm::RationalFunction>(model, formula); std::shared_ptr<PmcResult> result = std::make_shared<PmcResult>(); - result->resultFunction = (checkResult->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*model->getInitialStates().begin()]); + result->resultFunction = checkResult->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*model->getInitialStates().begin()]; storm::models::sparse::Dtmc<storm::RationalFunction>::ConstraintCollector constraintCollector(*(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>())); result->constraintsWellFormed = constraintCollector.getWellformedConstraints(); result->constraintsGraphPreserving = constraintCollector.getGraphPreservingConstraints(); return result; -}*/ +} // Define python bindings void define_core(py::module& m) { @@ -44,14 +68,7 @@ void define_core(py::module& m) { m.def("parse_formulas", &storm::parseFormulasForExplicit, "Parse explicit formulas", py::arg("formula_string")); m.def("parse_formulas_for_program", &storm::parseFormulasForProgram, "Parse formulas for program", py::arg("formula_string"), py::arg("program")); - m.def("build_model", &buildModel, "Build the model", py::arg("program"), py::arg("formula")); - m.def("build_model_from_prism_program", &storm::buildSymbolicModel<double>, "Build the model", py::arg("program"), py::arg("formulas")); - m.def("build_parametric_model_from_prism_program", &storm::buildSymbolicModel<storm::RationalFunction>, "Build the parametric model", py::arg("program"), py::arg("formulas")); - - //m.def("perform_state_elimination", &performStateElimination, "Perform state elimination"); - - //m.def("perform_bisimulation_parametric", static_cast<std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> (*)(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> const&, std::shared_ptr<const storm::logic::Formula> const&, storm::storage::BisimulationType)>(&storm::performBisimulationMinimization<storm::models::sparse::Model<storm::RationalFunction>>), "Perform bisimulation"); - + m.def("perform_state_elimination", &performStateElimination, "Perform state elimination", py::arg("model"), py::arg("formula")); // Program py::enum_<storm::prism::Program::ModelType>(m, "PrismModelType", "Type of the prism model") @@ -76,6 +93,10 @@ void define_core(py::module& m) { // Models + m.def("build_model", &buildModel, "Build the model", py::arg("program"), py::arg("formula")); + m.def("build_model_from_prism_program", &storm::buildSymbolicModel<double>, "Build the model", py::arg("program"), py::arg("formulas")); + m.def("build_parametric_model_from_prism_program", &storm::buildSymbolicModel<storm::RationalFunction>, "Build the parametric model", py::arg("program"), py::arg("formulas")); + py::enum_<storm::models::ModelType>(m, "ModelType", "Type of the model") .value("DTMC", storm::models::ModelType::Dtmc) .value("MDP", storm::models::ModelType::Mdp) @@ -96,36 +117,35 @@ void define_core(py::module& m) { py::class_<storm::models::sparse::Model<double>, std::shared_ptr<storm::models::sparse::Model<double>>>(m, "SparseModel", "A probabilistic model where transitions are represented by doubles and saved in a sparse matrix", py::base<storm::models::ModelBase>()) ; - py::class_<storm::models::sparse::Dtmc<double>, std::shared_ptr<storm::models::sparse::Dtmc<double>>>(m, "SparseDtmc", "DTMC in sparse representation", py::base<storm::models::sparse::Model<double>>()) ; - py::class_<storm::models::sparse::Mdp<double>, std::shared_ptr<storm::models::sparse::Mdp<double>>>(m, "SparseMdp", "MDP in sparse representation", py::base<storm::models::sparse::Model<double>>()) ; - py::class_<storm::models::sparse::Model<storm::RationalFunction>, std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>>>(m, "SparseParametricModel", "A probabilistic model where transitions are represented by rational functions and saved in a sparse matrix", py::base<storm::models::ModelBase>()) .def("collect_probability_parameters", &storm::models::sparse::getProbabilityParameters, "Collect parameters") ; - py::class_<storm::models::sparse::Dtmc<storm::RationalFunction>, std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>>>(m, "SparseParametricDtmc", "pDTMC in sparse representation", py::base<storm::models::sparse::Model<storm::RationalFunction>>()) ; - py::class_<storm::models::sparse::Mdp<storm::RationalFunction>, std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>>>(m, "SparseParametricMdp", "pMDP in sparse representation", py::base<storm::models::sparse::Model<storm::RationalFunction>>()) ; - - // PmcResult - /*py::class_<PmcResult, std::shared_ptr<PmcResult>>(m, "PmcResult", "Holds the results after parametric model checking") - .def_readwrite("result_function", &PmcResult::resultFunction, "Result as rational function") - //.def_readwrite("constraints_well_formed", &PmcResult::constraintsWellFormed, "Constraints ensuring well-formed probabilities") - //.def_readwrite("constraints_graph_preserving", &PmcResult::constraintsGraphPreserving, "Constraints ensuring graph preservation") - ;*/ - // Bisimulation - /*py::enum_<storm::storage::BisimulationType>(m, "BisimulationType", "Types of bisimulation") + py::enum_<storm::storage::BisimulationType>(m, "BisimulationType", "Types of bisimulation") .value("STRONG", storm::storage::BisimulationType::Strong) .value("WEAK", storm::storage::BisimulationType::Weak) - ;*/ + ; + m.def("perform_bisimulation", &performBisimulation<double>, "Perform bisimulation", py::arg("program"), py::arg("formula"), py::arg("bisimulation_type")); + m.def("perform_parametric_bisimulation", &performBisimulation<storm::RationalFunction>, "Perform bisimulation on parametric model", py::arg("program"), py::arg("formula"), py::arg("bisimulation_type")); + + // PmcResult + py::class_<PmcResult, std::shared_ptr<PmcResult>>(m, "PmcResult", "Holds the results after parametric model checking") + .def("__str__", &PmcResult::toString) + //.def("result_function", &PmcResult::getFunc, "Result as rational function") + //.def_readwrite("result_function", &PmcResult::resultFunction, "Result as rational function") + //.def_readwrite("constraints_well_formed", &PmcResult::constraintsWellFormed, "Constraints ensuring well-formed probabilities") + //.def_readwrite("constraints_graph_preserving", &PmcResult::constraintsGraphPreserving, "Constraints ensuring graph preservation") + ; + } diff --git a/stormpy/tests/core/test_core.py b/stormpy/tests/core/test_core.py index b740213e6..ece3771fc 100644 --- a/stormpy/tests/core/test_core.py +++ b/stormpy/tests/core/test_core.py @@ -3,3 +3,67 @@ import stormpy class TestCore: def test_init(self): stormpy.set_up("") + + def test_build_parametric_model_from_prism_program(self): + program = stormpy.parse_program("../examples/pdtmc/brp/brp_16_2.pm") + assert program.nr_modules() == 5 + assert program.model_type() == stormpy.PrismModelType.DTMC + assert program.has_undefined_constants() + prop = "P=? [F \"target\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_parametric_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 613 + assert model.nr_transitions() == 803 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.parametric() + + def test_bisimulation(self): + program = stormpy.parse_program("../examples/dtmc/crowds/crowds5_5.pm") + assert program.nr_modules() == 1 + assert program.model_type() == stormpy.PrismModelType.DTMC + prop = "P=? [F \"observe0Greater1\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 7403 + assert model.nr_transitions() == 13041 + assert model.model_type() == stormpy.ModelType.DTMC + assert not model.parametric() + model_bisim = stormpy.perform_bisimulation(model, formulas[0], stormpy.BisimulationType.STRONG) + assert model_bisim.nr_states() == 64 + assert model_bisim.nr_transitions() == 104 + assert model_bisim.model_type() == stormpy.ModelType.DTMC + assert not model_bisim.parametric() + + def test_parametric_bisimulation(self): + program = stormpy.parse_program("../examples/pdtmc/crowds/crowds_3-5.pm") + assert program.nr_modules() == 1 + assert program.model_type() == stormpy.PrismModelType.DTMC + assert program.has_undefined_constants() + prop = "P=? [F \"observe0Greater1\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_parametric_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 1367 + assert model.nr_transitions() == 2027 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.parametric() + model_bisim = stormpy.perform_parametric_bisimulation(model, formulas[0], stormpy.BisimulationType.STRONG) + assert model_bisim.nr_states() == 80 + assert model_bisim.nr_transitions() == 120 + assert model_bisim.model_type() == stormpy.ModelType.DTMC + assert model_bisim.parametric() + + def test_state_elimination(self): + import pycarl + program = stormpy.parse_program("../examples/pdtmc/brp/brp_16_2.pm") + prop = "P=? [F \"target\"]" + formulas = stormpy.parse_formulas_for_program(prop, program) + pair = stormpy.build_parametric_model_from_prism_program(program, formulas) + model = pair.model + assert model.nr_states() == 613 + assert model.nr_transitions() == 803 + assert model.model_type() == stormpy.ModelType.DTMC + assert model.parametric() + result = stormpy.perform_state_elimination(model, formulas[0]) diff --git a/stormpy/tests/core/test_parse.py b/stormpy/tests/core/test_parse.py index ee55f4150..909bef7a2 100644 --- a/stormpy/tests/core/test_parse.py +++ b/stormpy/tests/core/test_parse.py @@ -5,7 +5,7 @@ class TestParse: program = stormpy.parse_program("../examples/dtmc/die/die.pm") assert program.nr_modules() == 1 assert program.model_type() == stormpy.PrismModelType.DTMC - assert program.has_undefined_constants() == False + assert not program.has_undefined_constants() def test_parse_formula(self): prop = "P=? [F \"one\"]" @@ -22,7 +22,7 @@ class TestParse: assert model.nr_states() == 13 assert model.nr_transitions() == 20 assert model.model_type() == stormpy.ModelType.DTMC - assert model.parametric() == False + assert not model.parametric() def test_build_model(self): program = stormpy.parse_program("../examples/dtmc/die/die.pm") @@ -31,5 +31,4 @@ class TestParse: assert model.nr_states() == 13 assert model.nr_transitions() == 20 assert model.model_type() == stormpy.ModelType.DTMC - assert model.parametric() == True - + assert model.parametric()