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.

445 lines
18 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. import sys
  2. if sys.version_info[0] == 2:
  3. raise ImportError('Python 2.x is not supported for stormpy.')
  4. from . import core
  5. from .core import *
  6. from . import storage
  7. from .storage import *
  8. from ._config import *
  9. from .logic import *
  10. from .exceptions import *
  11. from pycarl import Variable # needed for building parametric models
  12. __version__ = "unknown"
  13. try:
  14. from ._version import __version__
  15. except ImportError:
  16. # We're running in a tree that doesn't have a _version.py, so we don't know what our version is.
  17. pass
  18. core._set_up("")
  19. def _convert_sparse_model(model, parametric=False):
  20. """
  21. Convert (parametric) model in sparse representation into model corresponding to exact model type.
  22. :param model: Sparse model.
  23. :param parametric: Flag indicating if the model is parametric.
  24. :return: Model corresponding to exact model type.
  25. """
  26. if parametric:
  27. assert model.supports_parameters
  28. if model.model_type == ModelType.DTMC:
  29. return model._as_sparse_pdtmc()
  30. elif model.model_type == ModelType.MDP:
  31. return model._as_sparse_pmdp()
  32. elif model.model_type == ModelType.CTMC:
  33. return model._as_sparse_pctmc()
  34. elif model.model_type == ModelType.MA:
  35. return model._as_sparse_pma()
  36. else:
  37. raise StormError("Not supported parametric model constructed")
  38. else:
  39. assert not model.supports_parameters
  40. if model.model_type == ModelType.DTMC:
  41. return model._as_sparse_dtmc()
  42. elif model.model_type == ModelType.MDP:
  43. return model._as_sparse_mdp()
  44. elif model.model_type == ModelType.POMDP:
  45. return model._as_sparse_pomdp()
  46. elif model.model_type == ModelType.CTMC:
  47. return model._as_sparse_ctmc()
  48. elif model.model_type == ModelType.MA:
  49. return model._as_sparse_ma()
  50. else:
  51. raise StormError("Not supported non-parametric model constructed")
  52. def _convert_symbolic_model(model, parametric=False):
  53. """
  54. Convert (parametric) model in symbolic representation into model corresponding to exact model type.
  55. :param model: Symbolic model.
  56. :param parametric: Flag indicating if the model is parametric.
  57. :return: Model corresponding to exact model type.
  58. """
  59. if parametric:
  60. assert model.supports_parameters
  61. if model.model_type == ModelType.DTMC:
  62. return model._as_symbolic_pdtmc()
  63. elif model.model_type == ModelType.MDP:
  64. return model._as_symbolic_pmdp()
  65. elif model.model_type == ModelType.CTMC:
  66. return model._as_symbolic_pctmc()
  67. elif model.model_type == ModelType.MA:
  68. return model._as_symbolic_pma()
  69. else:
  70. raise StormError("Not supported parametric model constructed")
  71. else:
  72. assert not model.supports_parameters
  73. if model.model_type == ModelType.DTMC:
  74. return model._as_symbolic_dtmc()
  75. elif model.model_type == ModelType.MDP:
  76. return model._as_symbolic_mdp()
  77. elif model.model_type == ModelType.CTMC:
  78. return model._as_symbolic_ctmc()
  79. elif model.model_type == ModelType.MA:
  80. return model._as_symbolic_ma()
  81. else:
  82. raise StormError("Not supported non-parametric model constructed")
  83. def build_model(symbolic_description, properties=None):
  84. """
  85. Build a model in sparse representation from a symbolic description.
  86. :param symbolic_description: Symbolic model description to translate into a model.
  87. :param List[Property] properties: List of properties that should be preserved during the translation. If None, then all properties are preserved.
  88. :return: Model in sparse representation.
  89. """
  90. return build_sparse_model(symbolic_description, properties=properties)
  91. def build_parametric_model(symbolic_description, properties=None):
  92. """
  93. Build a parametric model in sparse representation from a symbolic description.
  94. :param symbolic_description: Symbolic model description to translate into a model.
  95. :param List[Property] properties: List of properties that should be preserved during the translation. If None, then all properties are preserved.
  96. :return: Parametric model in sparse representation.
  97. """
  98. return build_sparse_parametric_model(symbolic_description, properties=properties)
  99. def build_sparse_model(symbolic_description, properties=None):
  100. """
  101. Build a model in sparse representation from a symbolic description.
  102. :param symbolic_description: Symbolic model description to translate into a model.
  103. :param List[Property] properties: List of properties that should be preserved during the translation. If None, then all properties are preserved.
  104. :return: Model in sparse representation.
  105. """
  106. if not symbolic_description.undefined_constants_are_graph_preserving:
  107. raise StormError("Program still contains undefined constants")
  108. if properties:
  109. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  110. intermediate = core._build_sparse_model_from_symbolic_description(symbolic_description, formulae)
  111. else:
  112. intermediate = core._build_sparse_model_from_symbolic_description(symbolic_description)
  113. return _convert_sparse_model(intermediate, parametric=False)
  114. def build_sparse_parametric_model(symbolic_description, properties=None):
  115. """
  116. Build a parametric model in sparse representation from a symbolic description.
  117. :param symbolic_description: Symbolic model description to translate into a model.
  118. :param List[Property] properties: List of properties that should be preserved during the translation. If None, then all properties are preserved.
  119. :return: Parametric model in sparse representation.
  120. """
  121. if not symbolic_description.undefined_constants_are_graph_preserving:
  122. raise StormError("Program still contains undefined constants")
  123. if properties:
  124. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  125. intermediate = core._build_sparse_parametric_model_from_symbolic_description(symbolic_description, formulae)
  126. else:
  127. intermediate = core._build_sparse_parametric_model_from_symbolic_description(symbolic_description)
  128. return _convert_sparse_model(intermediate, parametric=True)
  129. def build_symbolic_model(symbolic_description, properties=None):
  130. """
  131. Build a model in symbolic representation from a symbolic description.
  132. :param symbolic_description: Symbolic model description to translate into a model.
  133. :param List[Property] properties: List of properties that should be preserved during the translation. If None, then all properties are preserved.
  134. :return: Model in symbolic representation.
  135. """
  136. if not symbolic_description.undefined_constants_are_graph_preserving:
  137. raise StormError("Program still contains undefined constants")
  138. if properties:
  139. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  140. intermediate = core._build_symbolic_model_from_symbolic_description(symbolic_description, formulae)
  141. else:
  142. intermediate = core._build_symbolic_model_from_symbolic_description(symbolic_description)
  143. return _convert_symbolic_model(intermediate, parametric=False)
  144. def build_symbolic_parametric_model(symbolic_description, properties=None):
  145. """
  146. Build a parametric model in symbolic representation from a symbolic description.
  147. :param symbolic_description: Symbolic model description to translate into a model.
  148. :param List[Property] properties: List of properties that should be preserved during the translation. If None, then all properties are preserved.
  149. :return: Parametric model in symbolic representation.
  150. """
  151. if not symbolic_description.undefined_constants_are_graph_preserving:
  152. raise StormError("Program still contains undefined constants")
  153. if properties:
  154. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  155. intermediate = core._build_symbolic_parametric_model_from_symbolic_description(symbolic_description, formulae)
  156. else:
  157. intermediate = core._build_symbolic_parametric_model_from_symbolic_description(symbolic_description)
  158. return _convert_symbolic_model(intermediate, parametric=True)
  159. def build_model_from_drn(file):
  160. """
  161. Build a model in sparse representation from the explicit DRN representation.
  162. :param String file: DRN file containing the model.
  163. :return: Model in sparse representation.
  164. """
  165. intermediate = core._build_sparse_model_from_drn(file)
  166. return _convert_sparse_model(intermediate, parametric=False)
  167. def build_parametric_model_from_drn(file):
  168. """
  169. Build a parametric model in sparse representation from the explicit DRN representation.
  170. :param String file: DRN file containing the model.
  171. :return: Parametric model in sparse representation.
  172. """
  173. intermediate = core._build_sparse_parametric_model_from_drn(file)
  174. return _convert_sparse_model(intermediate, parametric=True)
  175. def perform_bisimulation(model, properties, bisimulation_type):
  176. """
  177. Perform bisimulation on model.
  178. :param model: Model.
  179. :param properties: Properties to preserve during bisimulation.
  180. :param bisimulation_type: Type of bisimulation (weak or strong).
  181. :return: Model after bisimulation.
  182. """
  183. return perform_sparse_bisimulation(model, properties, bisimulation_type)
  184. def perform_sparse_bisimulation(model, properties, bisimulation_type):
  185. """
  186. Perform bisimulation on model in sparse representation.
  187. :param model: Model.
  188. :param properties: Properties to preserve during bisimulation.
  189. :param bisimulation_type: Type of bisimulation (weak or strong).
  190. :return: Model after bisimulation.
  191. """
  192. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  193. if model.supports_parameters:
  194. return core._perform_parametric_bisimulation(model, formulae, bisimulation_type)
  195. else:
  196. return core._perform_bisimulation(model, formulae, bisimulation_type)
  197. def perform_symbolic_bisimulation(model, properties):
  198. """
  199. Perform bisimulation on model in symbolic representation.
  200. :param model: Model.
  201. :param properties: Properties to preserve during bisimulation.
  202. :return: Model after bisimulation.
  203. """
  204. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  205. bisimulation_type = BisimulationType.STRONG
  206. if model.supports_parameters:
  207. return core._perform_symbolic_parametric_bisimulation(model, formulae, bisimulation_type)
  208. else:
  209. return core._perform_symbolic_bisimulation(model, formulae, bisimulation_type)
  210. def model_checking(model, property, only_initial_states=False, extract_scheduler=False, environment=Environment()):
  211. """
  212. Perform model checking on model for property.
  213. :param model: Model.
  214. :param property: Property to check for.
  215. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  216. :param extract_scheduler: If True, try to extract a scheduler
  217. :return: Model checking result.
  218. :rtype: CheckResult
  219. """
  220. return check_model_sparse(model, property, only_initial_states=only_initial_states,
  221. extract_scheduler=extract_scheduler, environment=environment)
  222. def check_model_sparse(model, property, only_initial_states=False, extract_scheduler=False, environment=Environment()):
  223. """
  224. Perform model checking on model for property.
  225. :param model: Model.
  226. :param property: Property to check for.
  227. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  228. :param extract_scheduler: If True, try to extract a scheduler
  229. :return: Model checking result.
  230. :rtype: CheckResult
  231. """
  232. if isinstance(property, Property):
  233. formula = property.raw_formula
  234. else:
  235. formula = property
  236. if model.supports_parameters:
  237. task = core.ParametricCheckTask(formula, only_initial_states)
  238. task.set_produce_schedulers(extract_scheduler)
  239. return core._parametric_model_checking_sparse_engine(model, task, environment=environment)
  240. else:
  241. task = core.CheckTask(formula, only_initial_states)
  242. task.set_produce_schedulers(extract_scheduler)
  243. return core._model_checking_sparse_engine(model, task, environment=environment)
  244. def check_model_dd(model, property, only_initial_states=False, environment=Environment()):
  245. """
  246. Perform model checking using dd engine.
  247. :param model: Model.
  248. :param property: Property to check for.
  249. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  250. :return: Model checking result.
  251. :rtype: CheckResult
  252. """
  253. if isinstance(property, Property):
  254. formula = property.raw_formula
  255. else:
  256. formula = property
  257. if model.supports_parameters:
  258. task = core.ParametricCheckTask(formula, only_initial_states)
  259. return core._parametric_model_checking_dd_engine(model, task, environment=environment)
  260. else:
  261. task = core.CheckTask(formula, only_initial_states)
  262. return core._model_checking_dd_engine(model, task, environment=environment)
  263. def check_model_hybrid(model, property, only_initial_states=False, environment=Environment()):
  264. """
  265. Perform model checking using hybrid engine.
  266. :param model: Model.
  267. :param property: Property to check for.
  268. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  269. :return: Model checking result.
  270. :rtype: CheckResult
  271. """
  272. if isinstance(property, Property):
  273. formula = property.raw_formula
  274. else:
  275. formula = property
  276. if model.supports_parameters:
  277. task = core.ParametricCheckTask(formula, only_initial_states)
  278. return core._parametric_model_checking_hybrid_engine(model, task, environment=environment)
  279. else:
  280. task = core.CheckTask(formula, only_initial_states)
  281. return core._model_checking_hybrid_engine(model, task, environment=environment)
  282. def transform_to_sparse_model(model):
  283. """
  284. Transform model in symbolic representation into model in sparse representation.
  285. :param model: Symbolic model.
  286. :return: Sparse model.
  287. """
  288. if model.supports_parameters:
  289. return core._transform_to_sparse_parametric_model(model)
  290. else:
  291. return core._transform_to_sparse_model(model)
  292. def transform_to_discrete_time_model(model, properties):
  293. """
  294. Transform continuous-time model to discrete time model.
  295. :param model: Continuous-time model.
  296. :param properties: List of properties to transform as well.
  297. :return: Tuple (Discrete-time model, converted properties).
  298. """
  299. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  300. if model.supports_parameters:
  301. return core._transform_to_discrete_time_parametric_model(model, formulae)
  302. else:
  303. return core._transform_to_discrete_time_model(model, formulae)
  304. def prob01min_states(model, eventually_formula):
  305. assert type(eventually_formula) == logic.EventuallyFormula
  306. labelform = eventually_formula.subformula
  307. labelprop = core.Property("label-prop", labelform)
  308. phiStates = BitVector(model.nr_states, True)
  309. psiStates = model_checking(model, labelprop).get_truth_values()
  310. return compute_prob01min_states(model, phiStates, psiStates)
  311. def prob01max_states(model, eventually_formula):
  312. assert type(eventually_formula) == logic.EventuallyFormula
  313. labelform = eventually_formula.subformula
  314. labelprop = core.Property("label-prop", labelform)
  315. phiStates = BitVector(model.nr_states, True)
  316. psiStates = model_checking(model, labelprop).get_truth_values()
  317. return compute_prob01min_states(model, phiStates, psiStates)
  318. def compute_prob01_states(model, phi_states, psi_states):
  319. """
  320. Compute prob01 states for properties of the form phi_states until psi_states
  321. :param SparseDTMC model:
  322. :param BitVector phi_states:
  323. :param BitVector psi_states: Target states
  324. """
  325. if model.model_type != ModelType.DTMC:
  326. raise StormError("Prob 01 is only defined for DTMCs -- model must be a DTMC")
  327. if model.supports_parameters:
  328. return core._compute_prob01states_rationalfunc(model, phi_states, psi_states)
  329. else:
  330. return core._compute_prob01states_double(model, phi_states, psi_states)
  331. def compute_prob01min_states(model, phi_states, psi_states):
  332. if model.model_type == ModelType.DTMC:
  333. return compute_prob01_states(model, phi_states, psi_states)
  334. if model.supports_parameters:
  335. return core._compute_prob01states_min_rationalfunc(model, phi_states, psi_states)
  336. else:
  337. return core._compute_prob01states_min_double(model, phi_states, psi_states)
  338. def compute_prob01max_states(model, phi_states, psi_states):
  339. if model.model_type == ModelType.DTMC:
  340. return compute_prob01_states(model, phi_states, psi_states)
  341. if model.supports_parameters:
  342. return core._compute_prob01states_max_rationalfunc(model, phi_states, psi_states)
  343. else:
  344. return core._compute_prob01states_max_double(model, phi_states, psi_states)
  345. def topological_sort(model, forward=True, initial=[]):
  346. """
  347. :param model:
  348. :param forward:
  349. :return:
  350. """
  351. matrix = model.transition_matrix if forward else model.backward_transition_matrix
  352. if isinstance(model, storage._SparseParametricModel):
  353. return storage._topological_sort_rf(matrix, initial)
  354. elif isinstance(model, storage._SparseModel):
  355. return storage._topological_sort_double(matrix, initial)
  356. else:
  357. raise StormError("Unknown kind of model.")
  358. def construct_submodel(model, states, actions, keep_unreachable_states=True, options=SubsystemBuilderOptions()):
  359. """
  360. :param model: The model
  361. :param states: Which states should be preserved
  362. :param actions: Which actions should be preserved
  363. :param keep_unreachable_states: If False, run a reachability analysis.
  364. :return: A model with fewer states/actions
  365. """
  366. if isinstance(model, storage._SparseModel):
  367. return core._construct_subsystem_double(model, states, actions, keep_unreachable_states, options)
  368. else:
  369. raise NotImplementedError()