Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
393c401
Move core module to generic template bindings
linusheck Sep 10, 2026
3d57bac
Add explicit NotImplementedErrror if check_model_sparse is called on …
linusheck Sep 18, 2026
e2a9bc7
Add more explicit NotImplementedErrors
linusheck Sep 18, 2026
db71d57
More notimplementederrors for topologicalsort
linusheck Sep 18, 2026
21a52d7
Use same DdType
linusheck Sep 18, 2026
8377f56
Move DdType definition to storage and import in core
linusheck Sep 22, 2026
4a1f7ff
Remove define_sparse_matrix_nt, move to generic define_sparse_matrix def
linusheck Sep 22, 2026
d60fe03
Update src/core/core.cpp
linusheck Sep 22, 2026
ea18c61
Make define_build_sparse_model_defs generic, define_symbolic_model on…
linusheck Sep 22, 2026
2eb0e6c
Merge branch 'generic-types-core' of github.com:linusheck/stormpy int…
linusheck Sep 22, 2026
db08c9a
autoformat
linusheck Sep 22, 2026
eed28cb
move definitions to correct place
linusheck Sep 22, 2026
147cb4d
Remove guards against previously unsupported interval bindings
linusheck Sep 22, 2026
77e8c63
Update lib/stormpy/__init__.py
linusheck Sep 22, 2026
90832fb
Update lib/stormpy/__init__.py
linusheck Sep 22, 2026
4fbc14f
parametrize tests over value types
linusheck Sep 22, 2026
5145404
Organize tests a bit
linusheck Sep 22, 2026
980ae83
Merge branch 'generic-types-core' of github.com:linusheck/stormpy int…
linusheck Sep 22, 2026
c03a61c
Symbolic interval models are not a thing yet
linusheck Sep 22, 2026
16cd77f
transformContinuousToDiscreteTimeSparseModel only defined for non-in…
linusheck Sep 24, 2026
11f8b7d
Remove interval symbolic model declarations, and define create_filter…
linusheck Sep 24, 2026
02397ea
Refactor model builder definition with type handling
linusheck Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/building_models/04-building-models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def permissive_policy(state_valuation, action_index):
cond3 = json.loads(str(state_valuation.to_json()))["x1"] < 40
return cond1 or (cond2 and cond3)

constructor = stormpy.make_sparse_model_builder(prism_program, options, stormpy.StateValuationFunctionActionMaskDouble(permissive_policy))
constructor = stormpy.make_sparse_model_builder(prism_program, options, stormpy.StateValuationFunctionActionMask[float](permissive_policy))
model = constructor.build()
print(model)

Expand Down
250 changes: 100 additions & 150 deletions lib/stormpy/__init__.py

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions lib/stormpy/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,7 @@ class SparseSimulator(Simulator):
def __init__(self, model, seed=None):
super().__init__(seed)
self._model = model
if self._model.is_exact:
self._engine = stormpy._core._DiscreteTimeSparseModelSimulatorExact(model)
else:
self._engine = stormpy._core._DiscreteTimeSparseModelSimulatorDouble(model)
self._engine = stormpy.DiscreteTimeSparseModelSimulator(model)
if seed is not None:
self._engine.set_seed(seed)
self._state_valuations = None
Expand Down Expand Up @@ -234,7 +231,7 @@ def __init__(self, program, seed=None, options=stormpy.BuilderOptions()):
super().__init__(seed)
self._program = program
# TODO support exact arithmetic here
self._engine = stormpy._core._DiscreteTimePrismProgramSimulatorDouble(program, options)
self._engine = stormpy.DiscreteTimePrismProgramSimulator[float](program, options)
if seed is not None:
self._engine.set_seed(seed)
self.set_full_observability(self._program.model_type != stormpy.storage.PrismModelType.POMDP)
Expand Down
23 changes: 14 additions & 9 deletions lib/stormpy/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,45 +55,50 @@
deduce=_deduce_from_object(SparseMatrix.parameters_of, keyword="transition_matrix", default=(float,)),
)


# src/storage/model.cpp
_model_parameters = lambda source: SparseMatrix.parameters_of(source.transition_matrix)
def parameters_of_model(model):
"""Return the value-type parameter of a sparse model or model components."""

return SparseMatrix.parameters_of(model.transition_matrix)


SparseModel = TemplateClass("stormpy.storage.SparseModel", _storage, parameters=("ValueType",), deduce=_deduce_default(float))
SparseDtmc = TemplateClass(
"stormpy.storage.SparseDtmc",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword=("components", "other_model")),
deduce=_deduce_from_object(parameters_of_model, keyword=("components", "other_model")),
)
SparseMdp = TemplateClass(
"stormpy.storage.SparseMdp",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword=("components", "other_model")),
deduce=_deduce_from_object(parameters_of_model, keyword=("components", "other_model")),
)
SparsePomdp = TemplateClass(
"stormpy.storage.SparsePomdp",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword=("components", "other_model")),
deduce=_deduce_from_object(parameters_of_model, keyword=("components", "other_model")),
)
SparseCtmc = TemplateClass(
"stormpy.storage.SparseCtmc",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword=("components", "other_model")),
deduce=_deduce_from_object(parameters_of_model, keyword=("components", "other_model")),
)
SparseMA = TemplateClass(
"stormpy.storage.SparseMA",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword=("components", "other_model")),
deduce=_deduce_from_object(parameters_of_model, keyword=("components", "other_model")),
)
SparseSmg = TemplateClass(
"stormpy.storage.SparseSmg",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword=("components", "other_model")),
deduce=_deduce_from_object(parameters_of_model, keyword=("components", "other_model")),
)
SparseRewardModel = TemplateClass("stormpy.storage.SparseRewardModel", _storage, parameters=("ValueType",), deduce=_deduce_default(float))
SymbolicModel = TemplateClass("stormpy.storage.SymbolicModel", _storage, parameters=(_TemplateParameter("DdType", kind="value"), "ValueType"))
Expand All @@ -108,15 +113,15 @@
"stormpy.storage.MaximalEndComponentDecomposition",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword="model"),
deduce=_deduce_from_object(parameters_of_model, keyword="model"),
)

# src/storage/memorystructure.cpp
MemoryStructureBuilder = TemplateClass(
"stormpy.storage.MemoryStructureBuilder",
_storage,
parameters=("ValueType",),
deduce=_deduce_from_object(_model_parameters, keyword="model", position=1),
deduce=_deduce_from_object(parameters_of_model, keyword="model", position=1),
)
MemoryStructureProduct = TemplateClass("stormpy.storage.MemoryStructureProduct", _storage, parameters=("ValueType",), deduce=_deduce_default(float))

Expand Down
5 changes: 4 additions & 1 deletion src/core/analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

#include <storm/analysis/GraphConditions.h>

#include "src/binding_type_index.h"

// Define python bindings
void define_graph_constraints(py::module& m) {
// ConstraintCollector
py::classh<storm::analysis::ConstraintCollector<storm::RationalFunction>>(m, "ConstraintCollector", "Collector for constraints on parametric Markov chains")
stormpy::bindings::bindTemplateClass<storm::analysis::ConstraintCollector<storm::RationalFunction>>(
m, "ConstraintCollector", stormpy::bindings::typeIndex<storm::RationalFunction>(), "Collector for constraints on parametric Markov chains")
.def(py::init<storm::models::sparse::Model<storm::RationalFunction> const&>(), py::arg("model"))
.def_property_readonly("wellformed_constraints", &storm::analysis::ConstraintCollector<storm::RationalFunction>::getWellformedConstraints,
"Get the constraints ensuring a wellformed model")
Expand Down
4 changes: 2 additions & 2 deletions src/core/bisimulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ void define_bisimulation(py::module& m) {
// Bisimulation
m.def("_perform_bisimulation", &storm::api::performBisimulationMinimization<double>, "Perform bisimulation", py::arg("model"), py::arg("formulas"),
py::arg("bisimulation_type"), py::arg("graph_preserving"), py::arg("tolerance"));
m.def("_perform_parametric_bisimulation", &storm::api::performBisimulationMinimization<storm::RationalFunction>, "Perform bisimulation on parametric model",
m.def("_perform_bisimulation", &storm::api::performBisimulationMinimization<storm::RationalFunction>, "Perform bisimulation on parametric model",
py::arg("model"), py::arg("formulas"), py::arg("bisimulation_type"), py::arg("graph_preserving"), py::arg("tolerance"));
m.def("_perform_symbolic_bisimulation", &performBisimulationMinimization<storm::dd::DdType::Sylvan, double>, "Perform bisimulation", py::arg("model"),
py::arg("formulas"), py::arg("bisimulation_type"), py::arg("quotient_format"), py::arg("bisimulation_options"));
m.def("_perform_symbolic_parametric_bisimulation", &performBisimulationMinimization<storm::dd::DdType::Sylvan, storm::RationalFunction>,
m.def("_perform_symbolic_bisimulation", &performBisimulationMinimization<storm::dd::DdType::Sylvan, storm::RationalFunction>,
"Perform bisimulation on parametric model", py::arg("model"), py::arg("formulas"), py::arg("bisimulation_type"), py::arg("quotient_format"),
py::arg("bisimulation_options"));

Expand Down
86 changes: 30 additions & 56 deletions src/core/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <storm/utility/SignalHandler.h>
#include <storm/utility/initialize.h>

#include "src/binding_type_index.h"

void define_core(py::module& m) {
// Init
m.def(
Expand Down Expand Up @@ -103,30 +105,35 @@ std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> buildSymbolic
}
}

template<typename ValueType>
void define_explicit_model_builder(py::module& m, std::string const& name) {
m.def(name.c_str(), &storm::api::makeExplicitModelBuilder<ValueType>, "Construct a builder instance", py::arg("model_description"), py::arg("options"),
py::arg("action_mask") = nullptr, py::arg("exploration_options") = typename storm::builder::ExplicitModelBuilder<ValueType>::Options());

stormpy::bindings::bindTemplateClass<storm::builder::ExplicitModelBuilder<ValueType>>(m, "ExplicitModelBuilder", stormpy::bindings::typeIndex<ValueType>(),
"Model builder for sparse models")
.def("build", &storm::builder::ExplicitModelBuilder<ValueType>::build, "Build the model", py::call_guard<py::gil_scoped_release>())
.def("export_lookup", &storm::builder::ExplicitModelBuilder<ValueType>::exportExplicitStateLookup, "Export a lookup model");
}

template<typename ValueType>
void define_build_sparse_model_defs(py::module& m) {
std::string type;
std::string classType;
std::string desc;
if constexpr (std::is_same_v<ValueType, double>) {
type = "";
classType = "";
desc = "";
} else if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
type = "exact_";
classType = "Exact";
desc = "";
} else if constexpr (std::is_same_v<ValueType, storm::RationalFunction>) {
type = "parametric_";
classType = "Parametric";
desc = "parametric ";
} else if constexpr (std::is_same_v<ValueType, storm::Interval>) {
type = "interval_";
classType = "Interval";
desc = "interval ";
} else if constexpr (std::is_same_v<ValueType, storm::RationalInterval>) {
type = "exact_interval_";
classType = "ExactInterval";
desc = "exact interval ";
}

Expand All @@ -144,8 +151,8 @@ void define_build_sparse_model_defs(py::module& m) {
("Build the " + desc + "model from DRN" + (std::is_same_v<ValueType, storm::RationalFunction> ? " (parametric)" : "")).c_str(), py::arg("file"),
py::arg("options") = storm::parser::DirectEncodingParserOptions());

py::classh<typename storm::builder::ExplicitModelBuilder<ValueType>::Options>(m, ("Explicit" + classType + "ModelBuilderOptions").c_str(),
"Options for the explicit model builder")
stormpy::bindings::bindTemplateClass<typename storm::builder::ExplicitModelBuilder<ValueType>::Options>(
m, "ExplicitModelBuilderOptions", stormpy::bindings::typeIndex<ValueType>(), "Options for the explicit model builder")
.def(py::init<>(), "Create")
.def_readwrite("exploration_order", &storm::builder::ExplicitModelBuilder<ValueType>::Options::explorationOrder,
"The order in which to explore the model")
Expand All @@ -154,33 +161,18 @@ void define_build_sparse_model_defs(py::module& m) {
.def_readwrite("exploration_state_limit", &storm::builder::ExplicitModelBuilder<ValueType>::Options::explorationStateLimit,
"If set, no further states will be explored once the given number is exceeded.");

if constexpr (std::is_same_v<ValueType, double>) {
m.def("_build_symbolic_model_from_symbolic_description", &buildSymbolicModel<storm::dd::DdType::Sylvan, double>,
"Build the model in symbolic representation", py::arg("model_description"),
define_explicit_model_builder<ValueType>(m, type.empty() ? "make_sparse_model_builder" : "make_sparse_model_builder_" + type.substr(0, type.size() - 1));

if constexpr (!storm::IsIntervalType<ValueType>) {
m.def(("_build_symbolic_" + type + "model_from_symbolic_description").c_str(), &buildSymbolicModel<storm::dd::DdType::Sylvan, ValueType>,
("Build the " + desc + "model in symbolic representation").c_str(), py::arg("model_description"),
py::arg("formulas") = std::vector<std::shared_ptr<storm::logic::Formula const>>(), py::arg("environment"));
}

if constexpr (std::is_same_v<ValueType, double>) {
m.def("build_sparse_model_from_explicit", &storm::api::buildExplicitModel<double>, "Build the model model from explicit input",
py::arg("transition_file"), py::arg("labeling_file"), py::arg("state_reward_file") = "", py::arg("transition_reward_file") = "",
py::arg("choice_labeling_file") = "", py::arg("options") = storm::parser::ExplicitModelParserOptions());
m.def("make_sparse_model_builder", &storm::api::makeExplicitModelBuilder<double>, "Construct a builder instance", py::arg("model_description"),
py::arg("options"), py::arg("action_mask") = nullptr,
py::arg("exploration_options") = typename storm::builder::ExplicitModelBuilder<ValueType>::Options());
py::classh<storm::builder::ExplicitModelBuilder<double>>(m, "ExplicitModelBuilder", "Model builder for sparse models")
.def("build", &storm::builder::ExplicitModelBuilder<double>::build, "Build the model", py::call_guard<py::gil_scoped_release>())
.def("export_lookup", &storm::builder::ExplicitModelBuilder<double>::exportExplicitStateLookup, "Export a lookup model");
} else if constexpr (std::is_same_v<ValueType, storm::RationalFunction>) {
m.def("_build_symbolic_parametric_model_from_symbolic_description", &buildSymbolicModel<storm::dd::DdType::Sylvan, storm::RationalFunction>,
"Build the parametric model in symbolic representation", py::arg("model_description"),
py::arg("formulas") = std::vector<std::shared_ptr<storm::logic::Formula const>>(), py::arg("environment"));
m.def("make_sparse_model_builder_parametric", &storm::api::makeExplicitModelBuilder<storm::RationalFunction>, "Construct a builder instance",
py::arg("model_description"), py::arg("options"), py::arg("action_mask") = nullptr,
py::arg("exploration_options") = typename storm::builder::ExplicitModelBuilder<ValueType>::Options());
py::classh<storm::builder::ExplicitModelBuilder<storm::RationalFunction>>(m, "ExplicitParametricModelBuilder", "Model builder for sparse models")
.def("build", &storm::builder::ExplicitModelBuilder<storm::RationalFunction>::build, "Build the model", py::call_guard<py::gil_scoped_release>())
.def("export_lookup", &storm::builder::ExplicitModelBuilder<storm::RationalFunction>::exportExplicitStateLookup, "Export a lookup model");
} else if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
m.def("make_sparse_model_builder_exact", &storm::api::makeExplicitModelBuilder<storm::RationalNumber>, "Construct a builder instance",
py::arg("model_description"), py::arg("options"), py::arg("action_mask") = nullptr,
py::arg("exploration_options") = typename storm::builder::ExplicitModelBuilder<ValueType>::Options());
}
}

Expand Down Expand Up @@ -242,9 +234,11 @@ void define_build(py::module& m) {
.def("set_build_all_reward_models", &storm::builder::BuilderOptions::setBuildAllRewardModels, "Build with all reward models",
py::arg("new_value") = true);

py::classh<storm::generator::ActionMask<double>> actionmask(m, "ActionMaskDouble");
py::classh<storm::generator::StateValuationFunctionMask<double>> actfuncmask(m, "StateValuationFunctionActionMaskDouble", actionmask);
actfuncmask.def(py::init<std::function<bool(storm::expressions::SimpleValuation const&, uint64_t)>>(), py::arg("f"));
auto actionmask =
stormpy::bindings::bindTemplateClass<storm::generator::ActionMask<double>>(m, "ActionMask", stormpy::bindings::typeIndex<double>(), "Mask for actions");
stormpy::bindings::bindTemplateClass<storm::generator::StateValuationFunctionMask<double>>(
m, "StateValuationFunctionActionMask", stormpy::bindings::typeIndex<double>(), "Action mask based on state valuations", actionmask)
.def(py::init<std::function<bool(storm::expressions::SimpleValuation const&, uint64_t)>>(), py::arg("f"));
}

void define_optimality_type(py::module& m) {
Expand All @@ -270,28 +264,8 @@ void exportDRN(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, s

template<typename ValueType>
void define_export_drn(py::module& m) {
std::string prefix;
std::string suffix;
if constexpr (std::is_same_v<ValueType, double>) {
prefix = "";
suffix = "";
} else if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
prefix = "_exact";
suffix = "";
} else if constexpr (std::is_same_v<ValueType, storm::RationalFunction>) {
prefix = "_parametric";
suffix = "";
} else if constexpr (std::is_same_v<ValueType, storm::Interval>) {
prefix = "";
suffix = "_interval";
} else if constexpr (std::is_same_v<ValueType, storm::RationalInterval>) {
prefix = "_exact";
suffix = "_interval";
}

m.def(("_export" + prefix + "_to_drn" + suffix).c_str(), &exportDRN<ValueType>,
("Export " + (std::is_same_v<ValueType, storm::RationalFunction> ? std::string("parametric ") : std::string()) + "model in DRN format").c_str(),
py::arg("model"), py::arg("file"), py::arg("options") = storm::io::DirectEncodingExporterOptions());
m.def("_export_to_drn", &exportDRN<ValueType>, "Export model in DRN format", py::arg("model"), py::arg("file"),
py::arg("options") = storm::io::DirectEncodingExporterOptions());
}

void define_export(py::module& m) {
Expand Down
Loading
Loading