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.

481 lines
12 KiB

  1. {
  2. "cells": [
  3. {
  4. "cell_type": "markdown",
  5. "metadata": {},
  6. "source": [
  7. "# Getting Started\n",
  8. "\n",
  9. "Before starting with this guide, one should follow the instructions for [Installation](installation.ipynb)."
  10. ]
  11. },
  12. {
  13. "cell_type": "markdown",
  14. "metadata": {},
  15. "source": [
  16. "## A Quick Tour through Stormpy\n",
  17. "\n",
  18. "This guide is intended for people which have a basic understanding of probabilistic models and their verification. More details and further pointers to literature can be found on the\n",
  19. "[Storm website](http://www.stormchecker.org/).\n",
  20. "While we assume some very basic programming concepts, we refrain from using more advanced concepts of python throughout the guide.\n",
  21. "\n",
  22. "We start with a selection of high-level constructs in stormpy, and go into more details afterwards. More in-depth examples can be found in the [Advanced Examples](advanced_topics.ipynb).\n",
  23. "\n",
  24. "The code examples are also given in the [examples/](https://github.com/moves-rwth/stormpy/blob/master/examples/) folder. These boxes throughout the text will tell you which example contains the code discussed.\n",
  25. "\n",
  26. "We start by launching the python 3 interpreter:"
  27. ]
  28. },
  29. {
  30. "cell_type": "markdown",
  31. "metadata": {
  32. "hide-output": false
  33. },
  34. "source": [
  35. "```\n",
  36. "$ python3\n",
  37. "```"
  38. ]
  39. },
  40. {
  41. "cell_type": "markdown",
  42. "metadata": {},
  43. "source": [
  44. "First we import stormpy:"
  45. ]
  46. },
  47. {
  48. "cell_type": "code",
  49. "execution_count": null,
  50. "metadata": {
  51. "hide-output": false
  52. },
  53. "outputs": [],
  54. "source": [
  55. ">>> import stormpy"
  56. ]
  57. },
  58. {
  59. "cell_type": "markdown",
  60. "metadata": {},
  61. "source": [
  62. "### Building models\n",
  63. "\n",
  64. "[01-getting-started.py](https://github.com/moves-rwth/stormpy/blob/master/examples/01-getting-started.py)\n",
  65. "\n",
  66. "There are several ways to create a Markov chain.\n",
  67. "One of the easiest is to parse a description of such a Markov chain and to let Storm build the chain.\n",
  68. "\n",
  69. "Here, we build a Markov chain from a prism program.\n",
  70. "Stormpy comes with a small set of examples, which we use here:"
  71. ]
  72. },
  73. {
  74. "cell_type": "code",
  75. "execution_count": null,
  76. "metadata": {
  77. "hide-output": false
  78. },
  79. "outputs": [],
  80. "source": [
  81. ">>> import stormpy.examples\n",
  82. ">>> import stormpy.examples.files"
  83. ]
  84. },
  85. {
  86. "cell_type": "markdown",
  87. "metadata": {},
  88. "source": [
  89. "With this, we can now import the path of our prism file:"
  90. ]
  91. },
  92. {
  93. "cell_type": "code",
  94. "execution_count": null,
  95. "metadata": {
  96. "hide-output": false
  97. },
  98. "outputs": [],
  99. "source": [
  100. ">>> path = stormpy.examples.files.prism_dtmc_die\n",
  101. ">>> prism_program = stormpy.parse_prism_program(path)"
  102. ]
  103. },
  104. {
  105. "cell_type": "markdown",
  106. "metadata": {},
  107. "source": [
  108. "The `prism_program` can be translated into a Markov chain:"
  109. ]
  110. },
  111. {
  112. "cell_type": "code",
  113. "execution_count": null,
  114. "metadata": {
  115. "hide-output": false
  116. },
  117. "outputs": [],
  118. "source": [
  119. ">>> model = stormpy.build_model(prism_program)\n",
  120. ">>> print(\"Number of states: {}\".format(model.nr_states))"
  121. ]
  122. },
  123. {
  124. "cell_type": "code",
  125. "execution_count": null,
  126. "metadata": {},
  127. "outputs": [],
  128. "source": [
  129. ">>> print(\"Number of transitions: {}\".format(model.nr_transitions))"
  130. ]
  131. },
  132. {
  133. "cell_type": "markdown",
  134. "metadata": {},
  135. "source": [
  136. "This tells us that the model has 13 states and 20 transitions.\n",
  137. "\n",
  138. "Moreover, initial states and deadlocks are indicated with a labelling function. We can see the labels present in the model by:"
  139. ]
  140. },
  141. {
  142. "cell_type": "code",
  143. "execution_count": null,
  144. "metadata": {
  145. "hide-output": false
  146. },
  147. "outputs": [],
  148. "source": [
  149. ">>> print(\"Labels: {}\".format(model.labeling.get_labels()))"
  150. ]
  151. },
  152. {
  153. "cell_type": "markdown",
  154. "metadata": {},
  155. "source": [
  156. "We will investigate ways to examine the model in more detail later in [Investigating the model](#getting-started-investigating-the-model).\n",
  157. "\n",
  158. "\n",
  159. "<a id='getting-started-building-properties'></a>"
  160. ]
  161. },
  162. {
  163. "cell_type": "markdown",
  164. "metadata": {},
  165. "source": [
  166. "### Building properties\n",
  167. "\n",
  168. "[02-getting-started.py](https://github.com/moves-rwth/stormpy/blob/master/examples/02-getting-started.py)\n",
  169. "\n",
  170. "Storm takes properties in the prism-property format.\n",
  171. "To express that one is interested in the reachability of any state where the prism program variable `s` is 2, one would formulate:"
  172. ]
  173. },
  174. {
  175. "cell_type": "markdown",
  176. "metadata": {
  177. "hide-output": false
  178. },
  179. "source": [
  180. "```\n",
  181. "P=? [F s=2]\n",
  182. "```"
  183. ]
  184. },
  185. {
  186. "cell_type": "markdown",
  187. "metadata": {},
  188. "source": [
  189. "Stormpy can be used to parse this. As the variables in the property refer to a program, the program has to be passed as an additional parameter:"
  190. ]
  191. },
  192. {
  193. "cell_type": "code",
  194. "execution_count": null,
  195. "metadata": {
  196. "hide-output": false
  197. },
  198. "outputs": [],
  199. "source": [
  200. ">>> formula_str = \"P=? [F s=2]\"\n",
  201. ">>> properties = stormpy.parse_properties(formula_str, prism_program)"
  202. ]
  203. },
  204. {
  205. "cell_type": "markdown",
  206. "metadata": {},
  207. "source": [
  208. "Notice that properties is now a list of properties containing a single element.\n",
  209. "\n",
  210. "However, if we build the model as before, then the appropriate information that the variable `s=2` in some states is not present.\n",
  211. "In order to label the states accordingly, we should notify Storm upon building the model that we would like to preserve given properties.\n",
  212. "Storm will then add the labels accordingly:"
  213. ]
  214. },
  215. {
  216. "cell_type": "code",
  217. "execution_count": null,
  218. "metadata": {
  219. "hide-output": false
  220. },
  221. "outputs": [],
  222. "source": [
  223. ">>> model = stormpy.build_model(prism_program, properties)\n",
  224. ">>> print(\"Labels in the model: {}\".format(sorted(model.labeling.get_labels())))"
  225. ]
  226. },
  227. {
  228. "cell_type": "markdown",
  229. "metadata": {},
  230. "source": [
  231. "Model building however now behaves slightly different: Only the properties passed are preserved, which means that model building might skip parts of the model.\n",
  232. "In particular, to check the probability of eventually reaching a state `x` where `s=2`, successor states of `x` are not relevant:"
  233. ]
  234. },
  235. {
  236. "cell_type": "code",
  237. "execution_count": null,
  238. "metadata": {
  239. "hide-output": false
  240. },
  241. "outputs": [],
  242. "source": [
  243. ">>> print(\"Number of states: {}\".format(model.nr_states))"
  244. ]
  245. },
  246. {
  247. "cell_type": "markdown",
  248. "metadata": {},
  249. "source": [
  250. "If we consider another property, however, such as:"
  251. ]
  252. },
  253. {
  254. "cell_type": "markdown",
  255. "metadata": {
  256. "hide-output": false
  257. },
  258. "source": [
  259. "```\n",
  260. "P=? [F s=7 & d=2]\n",
  261. "```"
  262. ]
  263. },
  264. {
  265. "cell_type": "markdown",
  266. "metadata": {},
  267. "source": [
  268. "then Storm is only skipping exploration of successors of the particular state `y` where `s=7` and `d=2`. In this model, state `y` has a self-loop, so effectively, the whole model is explored.\n",
  269. "\n",
  270. "\n",
  271. "<a id='getting-started-checking-properties'></a>"
  272. ]
  273. },
  274. {
  275. "cell_type": "markdown",
  276. "metadata": {},
  277. "source": [
  278. "### Checking properties\n",
  279. "\n",
  280. "[03-getting-started.py](https://github.com/moves-rwth/stormpy/blob/master/examples/03-getting-started.py)\n",
  281. "\n",
  282. "The last lesson taught us to construct properties and models with matching state labels.\n",
  283. "Now default checking routines are just a simple command away:"
  284. ]
  285. },
  286. {
  287. "cell_type": "code",
  288. "execution_count": null,
  289. "metadata": {
  290. "hide-output": false
  291. },
  292. "outputs": [],
  293. "source": [
  294. ">>> properties = stormpy.parse_properties(formula_str, prism_program)\n",
  295. ">>> model = stormpy.build_model(prism_program, properties)\n",
  296. ">>> result = stormpy.model_checking(model, properties[0])"
  297. ]
  298. },
  299. {
  300. "cell_type": "markdown",
  301. "metadata": {},
  302. "source": [
  303. "The result may contain information about all states.\n",
  304. "Instead, we can iterate over the results:"
  305. ]
  306. },
  307. {
  308. "cell_type": "code",
  309. "execution_count": null,
  310. "metadata": {
  311. "hide-output": false
  312. },
  313. "outputs": [],
  314. "source": [
  315. ">>> assert result.result_for_all_states\n",
  316. ">>> for x in result.get_values():\n",
  317. "... pass # do something with x"
  318. ]
  319. },
  320. {
  321. "cell_type": "markdown",
  322. "metadata": {},
  323. "source": [
  324. "#### Results for all states\n",
  325. "\n",
  326. "Some model checking algorithms do not provide results for all states. In those cases, the result is not valid for all states, and to iterate over them, a different method is required. We will explain this later.\n",
  327. "\n",
  328. "A good way to get the result for the initial states is as follows:"
  329. ]
  330. },
  331. {
  332. "cell_type": "code",
  333. "execution_count": null,
  334. "metadata": {
  335. "hide-output": false
  336. },
  337. "outputs": [],
  338. "source": [
  339. ">>> initial_state = model.initial_states[0]\n",
  340. ">>> print(result.at(initial_state))"
  341. ]
  342. },
  343. {
  344. "cell_type": "markdown",
  345. "metadata": {},
  346. "source": [
  347. "\n",
  348. "<a id='getting-started-investigating-the-model'></a>"
  349. ]
  350. },
  351. {
  352. "cell_type": "markdown",
  353. "metadata": {},
  354. "source": [
  355. "### Investigating the model\n",
  356. "\n",
  357. "[04-getting-started.py](https://github.com/moves-rwth/stormpy/blob/master/examples/04-getting-started.py)\n",
  358. "\n",
  359. "One powerful part of the Storm model checker is to quickly create the Markov chain from higher-order descriptions, as seen above:"
  360. ]
  361. },
  362. {
  363. "cell_type": "code",
  364. "execution_count": null,
  365. "metadata": {
  366. "hide-output": false
  367. },
  368. "outputs": [],
  369. "source": [
  370. ">>> path = stormpy.examples.files.prism_dtmc_die\n",
  371. ">>> prism_program = stormpy.parse_prism_program(path)\n",
  372. ">>> model = stormpy.build_model(prism_program)"
  373. ]
  374. },
  375. {
  376. "cell_type": "markdown",
  377. "metadata": {},
  378. "source": [
  379. "In this example, we will exploit this, and explore the underlying Markov chain of the model.\n",
  380. "The most basic question might be what the type of the constructed model is:"
  381. ]
  382. },
  383. {
  384. "cell_type": "code",
  385. "execution_count": null,
  386. "metadata": {
  387. "hide-output": false
  388. },
  389. "outputs": [],
  390. "source": [
  391. ">>> print(model.model_type)"
  392. ]
  393. },
  394. {
  395. "cell_type": "markdown",
  396. "metadata": {},
  397. "source": [
  398. "We can also directly explore the underlying state space/matrix.\n",
  399. "Notice that this code can be applied to both deterministic and non-deterministic models:"
  400. ]
  401. },
  402. {
  403. "cell_type": "code",
  404. "execution_count": null,
  405. "metadata": {
  406. "hide-output": false
  407. },
  408. "outputs": [],
  409. "source": [
  410. ">>> for state in model.states:\n",
  411. "... for action in state.actions:\n",
  412. "... for transition in action.transitions:\n",
  413. "... print(\"From state {}, with probability {}, go to state {}\".format(state, transition.value(), transition.column))"
  414. ]
  415. },
  416. {
  417. "cell_type": "markdown",
  418. "metadata": {},
  419. "source": [
  420. "Let us go into some more details. For DTMCs, each state has (at most) one outgoing probability distribution.\n",
  421. "Thus:"
  422. ]
  423. },
  424. {
  425. "cell_type": "code",
  426. "execution_count": null,
  427. "metadata": {
  428. "hide-output": false
  429. },
  430. "outputs": [],
  431. "source": [
  432. ">>> for state in model.states:\n",
  433. "... assert len(state.actions) <= 1"
  434. ]
  435. },
  436. {
  437. "cell_type": "markdown",
  438. "metadata": {},
  439. "source": [
  440. "We can also check if a state is indeed an initial state. Notice that `model.initial_states` contains state ids, not states.:"
  441. ]
  442. },
  443. {
  444. "cell_type": "code",
  445. "execution_count": null,
  446. "metadata": {
  447. "hide-output": false
  448. },
  449. "outputs": [],
  450. "source": [
  451. ">>> for state in model.states:\n",
  452. "... if state.id in model.initial_states:\n",
  453. "... pass"
  454. ]
  455. }
  456. ],
  457. "metadata": {
  458. "date": 1598188121.7690735,
  459. "filename": "getting_started.rst",
  460. "kernelspec": {
  461. "display_name": "Python 3",
  462. "language": "python",
  463. "name": "python3"
  464. },
  465. "language_info": {
  466. "codemirror_mode": {
  467. "name": "ipython",
  468. "version": 3
  469. },
  470. "file_extension": ".py",
  471. "mimetype": "text/x-python",
  472. "name": "python",
  473. "nbconvert_exporter": "python",
  474. "pygments_lexer": "ipython3",
  475. "version": "3.8.2"
  476. },
  477. "title": "Getting Started"
  478. },
  479. "nbformat": 4,
  480. "nbformat_minor": 4
  481. }