hannah
4 years ago
committed by
Matthias Volk
No known key found for this signature in database
GPG Key ID: 83A57678F739FCD3
3 changed files with 200 additions and 0 deletions
-
1doc/source/advanced_topics.rst
-
132doc/source/doc/building_dtmcs.rst
-
67examples/building_dtmcs/01-building-dtmcs.py
@ -0,0 +1,132 @@ |
|||||
|
********************************** |
||||
|
Discrete-time Markov chains (DTMCs) |
||||
|
********************************** |
||||
|
|
||||
|
|
||||
|
Background |
||||
|
===================== |
||||
|
As described in :doc:`../getting_started`, |
||||
|
Storm can be used to translate a model description e.g. in form of a prism file into a Markov chain. |
||||
|
|
||||
|
Here, we use Stormpy to create the single components, to build a DTMC without parsing a model description. |
||||
|
We consider the previous example of the die. |
||||
|
|
||||
|
.. seealso:: `01-building-dtmcs.py <todo/02-gspns.py/examples/building_dtmcs/01-building-dtmcs.py>` |
||||
|
|
||||
|
In the following we create transition matrix, the state labeling and the reward models of a DTMC. |
||||
|
First, we import stormpy:: |
||||
|
|
||||
|
>>> import stormpy |
||||
|
|
||||
|
Transition Matrix |
||||
|
===================== |
||||
|
We begin by creating the matrix representing the transitions in the model in terms of probabilities. |
||||
|
For constructing the transition matrix, we use the SparseMatrixBuilder:: |
||||
|
|
||||
|
>>> builder = stormpy.SparseMatrixBuilder(rows = 0, columns = 0, entries = 0, force_dimensions = False, has_custom_row_grouping = False) |
||||
|
|
||||
|
Here, we start with an empty matrix to later insert more entries. |
||||
|
If the number of rows, columns and entries is known, the matrix can be constructed using these values. |
||||
|
|
||||
|
For DTMCs each state has at most one outgoing probability distribution. |
||||
|
Thus, we create matrix with trivial row grouping where each group contains one row representing the state action. |
||||
|
|
||||
|
We specify the transitions of the model, by adding values to the matrix where the column represents the target state. |
||||
|
All transitions are equipped with a probability defined by the value:: |
||||
|
|
||||
|
>>> builder.add_next_value(row = 0, column = 1, value = 0.5) |
||||
|
>>> builder.add_next_value(0, 2, 0.5) |
||||
|
>>> builder.add_next_value(1, 3, 0.5) |
||||
|
>>> builder.add_next_value(1, 4, 0.5) |
||||
|
>>> builder.add_next_value(2, 5, 0.5) |
||||
|
>>> builder.add_next_value(2, 6, 0.5) |
||||
|
>>> builder.add_next_value(3, 7, 0.5) |
||||
|
>>> builder.add_next_value(3, 1, 0.5) |
||||
|
>>> builder.add_next_value(4, 8, 0.5) |
||||
|
>>> builder.add_next_value(4, 9, 0.5) |
||||
|
>>> builder.add_next_value(5, 10, 0.5) |
||||
|
>>> builder.add_next_value(5, 11, 0.5) |
||||
|
>>> builder.add_next_value(6, 2, 0.5) |
||||
|
>>> builder.add_next_value(6, 12, 0.5) |
||||
|
|
||||
|
Lastly, we add a self-loop with probability one to the final states:: |
||||
|
|
||||
|
>>> for s in range(7,13): |
||||
|
>>> builder.add_next_value(s, s, 1) |
||||
|
|
||||
|
|
||||
|
Finally, we can build the matrix with updated row and columns count that both coincide with the number of states:: |
||||
|
|
||||
|
>>> transition_matrix = builder.build(13, 13) |
||||
|
|
||||
|
It should be noted that entries can only be inserted in ascending order, i.e. row by row and column by column. |
||||
|
Stormpy provides the possibility to build a sparse matrix using the numpy library <https://numpy.org/> |
||||
|
Instead of using the SparseMatrixBuilder, a sparse matrix can be build from a numpy array via the method stormpy.build_sparse_matrix. |
||||
|
|
||||
|
Labeling |
||||
|
==================== |
||||
|
|
||||
|
States can be labelled with sets of propositions, for example state 0 can be labelled with 'init'. |
||||
|
In order to specify the state labeling we create an empty labeling for the given number of states and add the labels to the labeling:: |
||||
|
|
||||
|
>>> state_labeling = stormpy.storage.StateLabeling(13) |
||||
|
|
||||
|
>>> labels = {'init', 'one', 'two', 'three', 'four', 'five', 'six', 'done', 'deadlock'} |
||||
|
>>> for label in labels: |
||||
|
>>> state_labeling.add_label(label) |
||||
|
|
||||
|
Next, we set teh associations between the labels and the respective states.:: |
||||
|
|
||||
|
>>> state_labeling.add_label_to_state('init', 0) |
||||
|
>>> state_labeling.add_label_to_state('one', 7) |
||||
|
>>> state_labeling.add_label_to_state('two', 8) |
||||
|
>>> state_labeling.add_label_to_state('three', 9) |
||||
|
>>> state_labeling.add_label_to_state('four', 10) |
||||
|
>>> state_labeling.add_label_to_state('five', 11) |
||||
|
>>> state_labeling.add_label_to_state('six', 12) |
||||
|
|
||||
|
To set the same label for multiple states, we can use a BitVector representation for the set of states:: |
||||
|
|
||||
|
>>> state_labeling.set_states('done', stormpy.BitVector(13, [7, 8, 9, 10, 11, 12])) |
||||
|
|
||||
|
In addition, it is possible to define a choice labeling, which is described in :doc:`building_ctmcs`. |
||||
|
|
||||
|
Reward Models |
||||
|
==================== |
||||
|
Stormpy supports multiple reward models such as state rewards, state-action rewards and as transition rewards. |
||||
|
In this example, the actions of states which satisfy s<7 acquire a reward of 1.0. |
||||
|
|
||||
|
The state-action rewards are represented by a vector, which is associated to a reward model named 'coin_flips':: |
||||
|
|
||||
|
>>> reward_models = {} |
||||
|
>>> action_reward = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] |
||||
|
>>> reward_models['coin_flips'] = stormpy.SparseRewardModel(optional_state_action_reward_vector = action_reward) |
||||
|
|
||||
|
Building the Model |
||||
|
==================== |
||||
|
|
||||
|
Next, we collect all components:: |
||||
|
|
||||
|
>>> components = stormpy.SparseModelComponents(transition_matrix=transition_matrix, state_labeling=state_labeling, reward_models=reward_models) |
||||
|
|
||||
|
And finally, we can build the DTMC:: |
||||
|
|
||||
|
>>> dtmc = stormpy.storage.SparseDtmc(components) |
||||
|
>>> print(dtmc) |
||||
|
-------------------------------------------------------------- |
||||
|
Model type: DTMC (sparse) |
||||
|
States: 13 |
||||
|
Transitions: 20 |
||||
|
Reward Models: coin_flips |
||||
|
State Labels: 9 labels |
||||
|
* three -> 1 item(s) |
||||
|
* six -> 1 item(s) |
||||
|
* done -> 6 item(s) |
||||
|
* four -> 1 item(s) |
||||
|
* five -> 1 item(s) |
||||
|
* deadlock -> 0 item(s) |
||||
|
* init -> 1 item(s) |
||||
|
* two -> 1 item(s) |
||||
|
* one -> 1 item(s) |
||||
|
Choice Labels: none |
||||
|
-------------------------------------------------------------- |
@ -0,0 +1,67 @@ |
|||||
|
import stormpy |
||||
|
import numpy as np |
||||
|
|
||||
|
|
||||
|
def example_building_dtmcs_01(): |
||||
|
|
||||
|
|
||||
|
# Use the SparseMatrixBuilder for constructing the transition matrix |
||||
|
builder = stormpy.SparseMatrixBuilder(rows = 0, columns = 0, entries = 0, force_dimensions = False, has_custom_row_grouping = False) |
||||
|
|
||||
|
# New Transition from state 0 to target state 1 with probability 0.5 |
||||
|
builder.add_next_value(row = 0, column = 1, value = 0.5) |
||||
|
builder.add_next_value(0, 2, 0.5) |
||||
|
builder.add_next_value(1, 3, 0.5) |
||||
|
builder.add_next_value(1, 4, 0.5) |
||||
|
builder.add_next_value(2, 5, 0.5) |
||||
|
builder.add_next_value(2, 6, 0.5) |
||||
|
builder.add_next_value(3, 7, 0.5) |
||||
|
builder.add_next_value(3, 1, 0.5) |
||||
|
builder.add_next_value(4, 8, 0.5) |
||||
|
builder.add_next_value(4, 9, 0.5) |
||||
|
builder.add_next_value(5, 10, 0.5) |
||||
|
builder.add_next_value(5, 11, 0.5) |
||||
|
builder.add_next_value(6, 2, 0.5) |
||||
|
builder.add_next_value(6, 12, 0.5) |
||||
|
|
||||
|
# Add transitions for the final states |
||||
|
for s in range(7,13): |
||||
|
builder.add_next_value(s, s, 1) |
||||
|
|
||||
|
# Build matrix |
||||
|
transition_matrix = builder.build(13, 13) |
||||
|
|
||||
|
# State labeling |
||||
|
state_labeling = stormpy.storage.StateLabeling(13) |
||||
|
|
||||
|
# Add labels |
||||
|
labels = {'init','one', 'two', 'three', 'four', 'five', 'six', 'done', 'deadlock'} |
||||
|
for label in labels: |
||||
|
state_labeling.add_label(label) |
||||
|
|
||||
|
# Add label to state |
||||
|
state_labeling.add_label_to_state('init', 0) |
||||
|
state_labeling.add_label_to_state('one', 7) |
||||
|
state_labeling.add_label_to_state('two', 8) |
||||
|
state_labeling.add_label_to_state('three', 9) |
||||
|
state_labeling.add_label_to_state('four', 10) |
||||
|
state_labeling.add_label_to_state('five', 11) |
||||
|
state_labeling.add_label_to_state('six', 12) |
||||
|
|
||||
|
# Add label 'done' to multiple states |
||||
|
state_labeling.set_states('done', stormpy.BitVector(13, [7, 8, 9, 10, 11, 12])) |
||||
|
|
||||
|
# Reward models: |
||||
|
reward_models = {} |
||||
|
# Create a vector representing the state-action rewards |
||||
|
action_reward = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] |
||||
|
reward_models['coin_flips'] = stormpy.SparseRewardModel(optional_state_action_reward_vector = action_reward) |
||||
|
|
||||
|
components = stormpy.SparseModelComponents(transition_matrix=transition_matrix, state_labeling=state_labeling, reward_models=reward_models) |
||||
|
|
||||
|
dtmc = stormpy.storage.SparseDtmc(components) |
||||
|
|
||||
|
print(dtmc) |
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
example_building_dtmcs_01() |
Write
Preview
Loading…
Cancel
Save
Reference in new issue