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.

474 lines
20 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. if model.is_sparse_model:
  221. return check_model_sparse(model, property, only_initial_states=only_initial_states,
  222. extract_scheduler=extract_scheduler, environment=environment)
  223. else:
  224. assert(model.is_symbolic_model)
  225. if extract_scheduler:
  226. raise StormError("Model checking based on dd engine does not support extracting schedulers right now.")
  227. return check_model_dd(model, property, only_initial_states=only_initial_states,
  228. environment=environment)
  229. def check_model_sparse(model, property, only_initial_states=False, extract_scheduler=False, environment=Environment()):
  230. """
  231. Perform model checking on model for property.
  232. :param model: Model.
  233. :param property: Property to check for.
  234. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  235. :param extract_scheduler: If True, try to extract a scheduler
  236. :return: Model checking result.
  237. :rtype: CheckResult
  238. """
  239. if isinstance(property, Property):
  240. formula = property.raw_formula
  241. else:
  242. formula = property
  243. if model.supports_parameters:
  244. task = core.ParametricCheckTask(formula, only_initial_states)
  245. task.set_produce_schedulers(extract_scheduler)
  246. return core._parametric_model_checking_sparse_engine(model, task, environment=environment)
  247. else:
  248. task = core.CheckTask(formula, only_initial_states)
  249. task.set_produce_schedulers(extract_scheduler)
  250. return core._model_checking_sparse_engine(model, task, environment=environment)
  251. def check_model_dd(model, property, only_initial_states=False, environment=Environment()):
  252. """
  253. Perform model checking using dd engine.
  254. :param model: Model.
  255. :param property: Property to check for.
  256. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  257. :return: Model checking result.
  258. :rtype: CheckResult
  259. """
  260. if isinstance(property, Property):
  261. formula = property.raw_formula
  262. else:
  263. formula = property
  264. if model.supports_parameters:
  265. task = core.ParametricCheckTask(formula, only_initial_states)
  266. return core._parametric_model_checking_dd_engine(model, task, environment=environment)
  267. else:
  268. task = core.CheckTask(formula, only_initial_states)
  269. return core._model_checking_dd_engine(model, task, environment=environment)
  270. def check_model_hybrid(model, property, only_initial_states=False, environment=Environment()):
  271. """
  272. Perform model checking using hybrid engine.
  273. :param model: Model.
  274. :param property: Property to check for.
  275. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  276. :return: Model checking result.
  277. :rtype: CheckResult
  278. """
  279. if isinstance(property, Property):
  280. formula = property.raw_formula
  281. else:
  282. formula = property
  283. if model.supports_parameters:
  284. task = core.ParametricCheckTask(formula, only_initial_states)
  285. return core._parametric_model_checking_hybrid_engine(model, task, environment=environment)
  286. else:
  287. task = core.CheckTask(formula, only_initial_states)
  288. return core._model_checking_hybrid_engine(model, task, environment=environment)
  289. def transform_to_sparse_model(model):
  290. """
  291. Transform model in symbolic representation into model in sparse representation.
  292. :param model: Symbolic model.
  293. :return: Sparse model.
  294. """
  295. if model.supports_parameters:
  296. return core._transform_to_sparse_parametric_model(model)
  297. else:
  298. return core._transform_to_sparse_model(model)
  299. def transform_to_discrete_time_model(model, properties):
  300. """
  301. Transform continuous-time model to discrete time model.
  302. :param model: Continuous-time model.
  303. :param properties: List of properties to transform as well.
  304. :return: Tuple (Discrete-time model, converted properties).
  305. """
  306. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  307. if model.supports_parameters:
  308. return core._transform_to_discrete_time_parametric_model(model, formulae)
  309. else:
  310. return core._transform_to_discrete_time_model(model, formulae)
  311. def prob01min_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 prob01max_states(model, eventually_formula):
  319. assert type(eventually_formula) == logic.EventuallyFormula
  320. labelform = eventually_formula.subformula
  321. labelprop = core.Property("label-prop", labelform)
  322. phiStates = BitVector(model.nr_states, True)
  323. psiStates = model_checking(model, labelprop).get_truth_values()
  324. return compute_prob01min_states(model, phiStates, psiStates)
  325. def compute_prob01_states(model, phi_states, psi_states):
  326. """
  327. Compute prob01 states for properties of the form phi_states until psi_states
  328. :param SparseDTMC model:
  329. :param BitVector phi_states:
  330. :param BitVector psi_states: Target states
  331. """
  332. if model.model_type != ModelType.DTMC:
  333. raise StormError("Prob 01 is only defined for DTMCs -- model must be a DTMC")
  334. if model.supports_parameters:
  335. return core._compute_prob01states_rationalfunc(model, phi_states, psi_states)
  336. else:
  337. return core._compute_prob01states_double(model, phi_states, psi_states)
  338. def compute_prob01min_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_min_rationalfunc(model, phi_states, psi_states)
  343. else:
  344. return core._compute_prob01states_min_double(model, phi_states, psi_states)
  345. def compute_prob01max_states(model, phi_states, psi_states):
  346. if model.model_type == ModelType.DTMC:
  347. return compute_prob01_states(model, phi_states, psi_states)
  348. if model.supports_parameters:
  349. return core._compute_prob01states_max_rationalfunc(model, phi_states, psi_states)
  350. else:
  351. return core._compute_prob01states_max_double(model, phi_states, psi_states)
  352. def topological_sort(model, forward=True, initial=[]):
  353. """
  354. :param model:
  355. :param forward:
  356. :return:
  357. """
  358. matrix = model.transition_matrix if forward else model.backward_transition_matrix
  359. if isinstance(model, storage._SparseParametricModel):
  360. return storage._topological_sort_rf(matrix, initial)
  361. elif isinstance(model, storage._SparseModel):
  362. return storage._topological_sort_double(matrix, initial)
  363. else:
  364. raise StormError("Unknown kind of model.")
  365. def construct_submodel(model, states, actions, keep_unreachable_states=True, options=SubsystemBuilderOptions()):
  366. """
  367. :param model: The model
  368. :param states: Which states should be preserved
  369. :param actions: Which actions should be preserved
  370. :param keep_unreachable_states: If False, run a reachability analysis.
  371. :return: A model with fewer states/actions
  372. """
  373. if isinstance(model, storage._SparseModel):
  374. return core._construct_subsystem_double(model, states, actions, keep_unreachable_states, options)
  375. else:
  376. raise NotImplementedError()
  377. def parse_properties(properties, context = None, filters = None):
  378. """
  379. :param properties: A string with the pctl properties
  380. :param context: A symbolic model that gives meaning to variables and constants.
  381. :param filters: filters, if applicable.
  382. :return: A list of properties
  383. """
  384. if context is None:
  385. return core.parse_properties_without_context(properties, filters)
  386. elif type(context) == core.SymbolicModelDescription:
  387. if context.is_prism_program():
  388. return core.parse_properties_for_prism_program(properties, context.as_prism_program(), filters)
  389. else:
  390. core.parse_properties_for_prism_program(properties, context.as_jani_model(), filters)
  391. elif type(context) == storage.PrismProgram:
  392. return core.parse_properties_for_prism_program(properties, context, filters)
  393. elif type(context) == storage.JaniModel:
  394. core.parse_properties_for_jani_model(properties, context, filters)
  395. else:
  396. raise StormError("Unclear context. Please pass a symbolic model description")