From 6f347ee3549aa791ee9134f88bf4534c0165b809 Mon Sep 17 00:00:00 2001 From: Tom Janson Date: Sun, 18 Dec 2016 00:37:05 +0100 Subject: [PATCH] add ShortestPathsGenerator binding (ctors, TODO: rest) --- src/utility/shortestPaths.cpp | 60 ++++++++++++----------------- tests/utility/test_shortestpaths.py | 57 +++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 tests/utility/test_shortestpaths.py diff --git a/src/utility/shortestPaths.cpp b/src/utility/shortestPaths.cpp index 89caa27..4313969 100644 --- a/src/utility/shortestPaths.cpp +++ b/src/utility/shortestPaths.cpp @@ -1,22 +1,22 @@ #include "shortestPaths.h" #include "storm/utility/shortestPaths.h" +#include #include +#include void define_ksp(py::module& m) { - using Path = storm::utility::ksp::Path; - using state_t = storm::utility::ksp::state_t; + // long types shortened for readability + using Path = storm::utility::ksp::Path; + using state_t = storm::utility::ksp::state_t; + using ShortestPathsGenerator = storm::utility::ksp::ShortestPathsGenerator; + using Model = storm::models::sparse::Model; + using BitVector = storm::storage::BitVector; - // (k-shortest) Path py::class_(m, "Path") - // Fuck all this. FIXME - - //.def(py::init, unsigned long, double>()) // does not work (because it's an aggregate initialized struct?) - - // this may or may not be working (i.e., initializing with the values as expected) - // https://pybind11.readthedocs.io/en/latest/advanced/classes.html#custom-constructors + // overload constructor rather than dealing with boost::optional .def("__init__", [](Path &instance, state_t preNode, unsigned long preK, double distance) { new (&instance) Path { boost::optional(preNode), preK, distance }; }, "predecessorNode"_a, "predecessorK"_a, "distance"_a) @@ -25,36 +25,24 @@ void define_ksp(py::module& m) { new (&instance) Path { boost::none, preK, distance }; }, "predecessorK"_a, "distance"_a) - // this actually seemed to work, once!, but not anymore - .def(py::self == py::self) - - .def("__repr__", - [](Path const& a) { - // shit this is ugly. but it's a proof of concept -- at least it works - std::string str = ""; + return oss.str(); }) - .def_readwrite("predecessorNode", &Path::predecessorNode) // does not work (again due to struct??) FIXME + .def_readwrite("predecessorNode", &Path::predecessorNode) // TODO (un-)wrap boost::optional so it's usable .def_readwrite("predecessorK", &Path::predecessorK) .def_readwrite("distance", &Path::distance) - ; - - // TODO continue - /* - // ShortestPathsGenerator - py::class_>(m, "ShortestPathsGenerator") - ; - */ + ; + + py::class_(m, "ShortestPathsGenerator") + .def(py::init(), "model"_a, "target_bitvector"_a) + .def(py::init(), "model"_a, "target_state"_a) + .def(py::init const&>(), "model"_a, "target_state_list"_a) + .def(py::init(), "model"_a, "target_label"_a) + ; } \ No newline at end of file diff --git a/tests/utility/test_shortestpaths.py b/tests/utility/test_shortestpaths.py new file mode 100644 index 0000000..102b5fc --- /dev/null +++ b/tests/utility/test_shortestpaths.py @@ -0,0 +1,57 @@ +import stormpy +import stormpy.logic +from stormpy.storage import BitVector +from stormpy.utility import ShortestPathsGenerator +from helpers.helper import get_example_path + +import pytest + + +@pytest.fixture +def test_model(scope="module", program_path=get_example_path("dtmc", "die.pm"), raw_formula="P=? [ F \"one\" ]"): + program = stormpy.parse_prism_program(program_path) + formulas = stormpy.parse_formulas_for_prism_program(raw_formula, program) + test_model = stormpy.build_model(program, formulas[0]) + return test_model + + +@pytest.fixture +def test_state(test_model): + some_state = 7 + assert test_model.nr_states > some_state, "test model too small" + return some_state + + +@pytest.fixture +def test_state_list(test_model): + some_state_list = [4, 5, 7] + assert test_model.nr_states > max(some_state_list), "test model too small" + return some_state_list + + +@pytest.fixture +def test_state_bitvector(test_model, test_state_list): + return BitVector(length=test_model.nr_states, set_entries=test_state_list) + + +@pytest.fixture +def test_label(test_model): + some_label = "one" + assert some_label in test_model.labels, "test model does not contain label '" + some_label + "'" + return some_label + + +class TestShortestPaths: + def test_spg_ctor_bitvector_target(self, test_model, test_state_bitvector): + _ = ShortestPathsGenerator(test_model, test_state_bitvector) + + def test_spg_ctor_single_state_target(self, test_model, test_state): + _ = ShortestPathsGenerator(test_model, test_state) + + def test_spg_ctor_state_list_target(self, test_model, test_state_list): + _ = ShortestPathsGenerator(test_model, test_state_list) + + def test_spg_ctor_label_target(self, test_model, test_label): + _ = ShortestPathsGenerator(test_model, test_label) + + # TODO: add tests that check actual functionality