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.

492 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, options = DirectEncodingParserOptions()):
  160. """
  161. Build a model in sparse representation from the explicit DRN representation.
  162. :param String file: DRN file containing the model.
  163. :param DirectEncodingParserOptions: Options for the parser.
  164. :return: Model in sparse representation.
  165. """
  166. intermediate = core._build_sparse_model_from_drn(file, options)
  167. return _convert_sparse_model(intermediate, parametric=False)
  168. def build_parametric_model_from_drn(file, options = DirectEncodingParserOptions()):
  169. """
  170. Build a parametric model in sparse representation from the explicit DRN representation.
  171. :param String file: DRN file containing the model.
  172. :param DirectEncodingParserOptions: Options for the parser.
  173. :return: Parametric model in sparse representation.
  174. """
  175. intermediate = core._build_sparse_parametric_model_from_drn(file, options)
  176. return _convert_sparse_model(intermediate, parametric=True)
  177. def perform_bisimulation(model, properties, bisimulation_type):
  178. """
  179. Perform bisimulation on model.
  180. :param model: Model.
  181. :param properties: Properties to preserve during bisimulation.
  182. :param bisimulation_type: Type of bisimulation (weak or strong).
  183. :return: Model after bisimulation.
  184. """
  185. return perform_sparse_bisimulation(model, properties, bisimulation_type)
  186. def perform_sparse_bisimulation(model, properties, bisimulation_type):
  187. """
  188. Perform bisimulation on model in sparse representation.
  189. :param model: Model.
  190. :param properties: Properties to preserve during bisimulation.
  191. :param bisimulation_type: Type of bisimulation (weak or strong).
  192. :return: Model after bisimulation.
  193. """
  194. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  195. if model.supports_parameters:
  196. return core._perform_parametric_bisimulation(model, formulae, bisimulation_type)
  197. else:
  198. return core._perform_bisimulation(model, formulae, bisimulation_type)
  199. def perform_symbolic_bisimulation(model, properties):
  200. """
  201. Perform bisimulation on model in symbolic representation.
  202. :param model: Model.
  203. :param properties: Properties to preserve during bisimulation.
  204. :return: Model after bisimulation.
  205. """
  206. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  207. bisimulation_type = BisimulationType.STRONG
  208. if model.supports_parameters:
  209. return core._perform_symbolic_parametric_bisimulation(model, formulae, bisimulation_type)
  210. else:
  211. return core._perform_symbolic_bisimulation(model, formulae, bisimulation_type)
  212. def model_checking(model, property, only_initial_states=False, extract_scheduler=False, environment=Environment()):
  213. """
  214. Perform model checking on model for property.
  215. :param model: Model.
  216. :param property: Property to check for.
  217. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  218. :param extract_scheduler: If True, try to extract a scheduler
  219. :return: Model checking result.
  220. :rtype: CheckResult
  221. """
  222. if model.is_sparse_model:
  223. return check_model_sparse(model, property, only_initial_states=only_initial_states,
  224. extract_scheduler=extract_scheduler, environment=environment)
  225. else:
  226. assert (model.is_symbolic_model)
  227. if extract_scheduler:
  228. raise StormError("Model checking based on dd engine does not support extracting schedulers right now.")
  229. return check_model_dd(model, property, only_initial_states=only_initial_states,
  230. environment=environment)
  231. def check_model_sparse(model, property, only_initial_states=False, extract_scheduler=False, environment=Environment()):
  232. """
  233. Perform model checking on model for property.
  234. :param model: Model.
  235. :param property: Property to check for.
  236. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  237. :param extract_scheduler: If True, try to extract a scheduler
  238. :return: Model checking result.
  239. :rtype: CheckResult
  240. """
  241. if isinstance(property, Property):
  242. formula = property.raw_formula
  243. else:
  244. formula = property
  245. if model.supports_parameters:
  246. task = core.ParametricCheckTask(formula, only_initial_states)
  247. task.set_produce_schedulers(extract_scheduler)
  248. return core._parametric_model_checking_sparse_engine(model, task, environment=environment)
  249. else:
  250. task = core.CheckTask(formula, only_initial_states)
  251. task.set_produce_schedulers(extract_scheduler)
  252. return core._model_checking_sparse_engine(model, task, environment=environment)
  253. def check_model_dd(model, property, only_initial_states=False, environment=Environment()):
  254. """
  255. Perform model checking using dd engine.
  256. :param model: Model.
  257. :param property: Property to check for.
  258. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  259. :return: Model checking result.
  260. :rtype: CheckResult
  261. """
  262. if isinstance(property, Property):
  263. formula = property.raw_formula
  264. else:
  265. formula = property
  266. if model.supports_parameters:
  267. task = core.ParametricCheckTask(formula, only_initial_states)
  268. return core._parametric_model_checking_dd_engine(model, task, environment=environment)
  269. else:
  270. task = core.CheckTask(formula, only_initial_states)
  271. return core._model_checking_dd_engine(model, task, environment=environment)
  272. def check_model_hybrid(model, property, only_initial_states=False, environment=Environment()):
  273. """
  274. Perform model checking using hybrid engine.
  275. :param model: Model.
  276. :param property: Property to check for.
  277. :param only_initial_states: If True, only results for initial states are computed, otherwise for all states.
  278. :return: Model checking result.
  279. :rtype: CheckResult
  280. """
  281. if isinstance(property, Property):
  282. formula = property.raw_formula
  283. else:
  284. formula = property
  285. if model.supports_parameters:
  286. task = core.ParametricCheckTask(formula, only_initial_states)
  287. return core._parametric_model_checking_hybrid_engine(model, task, environment=environment)
  288. else:
  289. task = core.CheckTask(formula, only_initial_states)
  290. return core._model_checking_hybrid_engine(model, task, environment=environment)
  291. def transform_to_sparse_model(model):
  292. """
  293. Transform model in symbolic representation into model in sparse representation.
  294. :param model: Symbolic model.
  295. :return: Sparse model.
  296. """
  297. if model.supports_parameters:
  298. return core._transform_to_sparse_parametric_model(model)
  299. else:
  300. return core._transform_to_sparse_model(model)
  301. def transform_to_discrete_time_model(model, properties):
  302. """
  303. Transform continuous-time model to discrete time model.
  304. :param model: Continuous-time model.
  305. :param properties: List of properties to transform as well.
  306. :return: Tuple (Discrete-time model, converted properties).
  307. """
  308. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  309. if model.supports_parameters:
  310. return core._transform_to_discrete_time_parametric_model(model, formulae)
  311. else:
  312. return core._transform_to_discrete_time_model(model, formulae)
  313. def eliminate_non_markovian_chains(ma, properties, label_behavior):
  314. """
  315. Eliminate chains of non-Markovian states if possible.
  316. :param ma: Markov automaton.
  317. :param properties: List of properties to transform as well.
  318. :param label_behavior: Behavior of labels while elimination.
  319. :return: Tuple (converted MA, converted properties).
  320. """
  321. formulae = [(prop.raw_formula if isinstance(prop, Property) else prop) for prop in properties]
  322. if ma.supports_parameters:
  323. return core._eliminate_non_markovian_chains_parametric(ma, formulae, label_behavior)
  324. else:
  325. return core._eliminate_non_markovian_chains(ma, formulae, label_behavior)
  326. def prob01min_states(model, eventually_formula):
  327. assert type(eventually_formula) == logic.EventuallyFormula
  328. labelform = eventually_formula.subformula
  329. labelprop = core.Property("label-prop", labelform)
  330. phiStates = BitVector(model.nr_states, True)
  331. psiStates = model_checking(model, labelprop).get_truth_values()
  332. return compute_prob01min_states(model, phiStates, psiStates)
  333. def prob01max_states(model, eventually_formula):
  334. assert type(eventually_formula) == logic.EventuallyFormula
  335. labelform = eventually_formula.subformula
  336. labelprop = core.Property("label-prop", labelform)
  337. phiStates = BitVector(model.nr_states, True)
  338. psiStates = model_checking(model, labelprop).get_truth_values()
  339. return compute_prob01min_states(model, phiStates, psiStates)
  340. def compute_prob01_states(model, phi_states, psi_states):
  341. """
  342. Compute prob01 states for properties of the form phi_states until psi_states
  343. :param SparseDTMC model:
  344. :param BitVector phi_states:
  345. :param BitVector psi_states: Target states
  346. """
  347. if model.model_type != ModelType.DTMC:
  348. raise StormError("Prob 01 is only defined for DTMCs -- model must be a DTMC")
  349. if model.supports_parameters:
  350. return core._compute_prob01states_rationalfunc(model, phi_states, psi_states)
  351. else:
  352. return core._compute_prob01states_double(model, phi_states, psi_states)
  353. def compute_prob01min_states(model, phi_states, psi_states):
  354. if model.model_type == ModelType.DTMC:
  355. return compute_prob01_states(model, phi_states, psi_states)
  356. if model.supports_parameters:
  357. return core._compute_prob01states_min_rationalfunc(model, phi_states, psi_states)
  358. else:
  359. return core._compute_prob01states_min_double(model, phi_states, psi_states)
  360. def compute_prob01max_states(model, phi_states, psi_states):
  361. if model.model_type == ModelType.DTMC:
  362. return compute_prob01_states(model, phi_states, psi_states)
  363. if model.supports_parameters:
  364. return core._compute_prob01states_max_rationalfunc(model, phi_states, psi_states)
  365. else:
  366. return core._compute_prob01states_max_double(model, phi_states, psi_states)
  367. def topological_sort(model, forward=True, initial=[]):
  368. """
  369. :param model:
  370. :param forward:
  371. :return:
  372. """
  373. matrix = model.transition_matrix if forward else model.backward_transition_matrix
  374. if isinstance(model, storage._SparseParametricModel):
  375. return storage._topological_sort_rf(matrix, initial)
  376. elif isinstance(model, storage._SparseModel):
  377. return storage._topological_sort_double(matrix, initial)
  378. else:
  379. raise StormError("Unknown kind of model.")
  380. def construct_submodel(model, states, actions, keep_unreachable_states=True, options=SubsystemBuilderOptions()):
  381. """
  382. :param model: The model
  383. :param states: Which states should be preserved
  384. :param actions: Which actions should be preserved
  385. :param keep_unreachable_states: If False, run a reachability analysis.
  386. :return: A model with fewer states/actions
  387. """
  388. if isinstance(model, storage._SparseModel):
  389. return core._construct_subsystem_double(model, states, actions, keep_unreachable_states, options)
  390. else:
  391. raise NotImplementedError()
  392. def parse_properties(properties, context=None, filters=None):
  393. """
  394. :param properties: A string with the pctl properties
  395. :param context: A symbolic model that gives meaning to variables and constants.
  396. :param filters: filters, if applicable.
  397. :return: A list of properties
  398. """
  399. if context is None:
  400. return core.parse_properties_without_context(properties, filters)
  401. elif type(context) == core.SymbolicModelDescription:
  402. if context.is_prism_program():
  403. return core.parse_properties_for_prism_program(properties, context.as_prism_program(), filters)
  404. else:
  405. core.parse_properties_for_prism_program(properties, context.as_jani_model(), filters)
  406. elif type(context) == storage.PrismProgram:
  407. return core.parse_properties_for_prism_program(properties, context, filters)
  408. elif type(context) == storage.JaniModel:
  409. core.parse_properties_for_jani_model(properties, context, filters)
  410. else:
  411. raise StormError("Unclear context. Please pass a symbolic model description")