Skip to content

Commit a093e64

Browse files
committed
add example to README
1 parent ada56c6 commit a093e64

3 files changed

Lines changed: 62 additions & 16 deletions

File tree

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@ ats.initial_states = [ats.num_states - 1]
2424
umbi.ats.write(ats, "out.umb")
2525
```
2626

27+
Here is another example where we create a simple CTMC:
28+
29+
```python
30+
import umbi
31+
from fractions import Fraction
32+
33+
ats = umbi.ats.SimpleAts()
34+
ats.time = umbi.ats.TimeType.STOCHASTIC
35+
ats.num_states = 3
36+
ats.initial_states = [0]
37+
ats.state_to_exit_rate = [3/2, Fraction(7,3), 1]
38+
ats.new_state_choice(state=2, targets=[2], probs=[1])
39+
ats.new_state_choice(state=1, targets=list(ats.states), target_prob=lambda s: Fraction(1,ats.num_states))
40+
ats.new_state_choice(state=0, targets=[1,2], probs=[1/2, 1/2])
41+
annotation = ats.new_ap_annotation("deadlock")
42+
annotation.state_values = [False, False, True]
43+
44+
umbi.ats.write(ats, "out.umb")
45+
```
46+
2747
More examples can be found in the [examples](./examples) folder.
2848

2949
## API

umbi/ats/ats_to_umb.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,4 +335,5 @@ def write(ats: SimpleAts, umbpath: str | pathlib.Path) -> None:
335335
:param umbpath: path to the umbfile to write to
336336
"""
337337
umb = explicit_ats_to_explicit_umb(ats)
338+
print(umb.index)
338339
umbi.umb.write(umb, umbpath)

umbi/ats/choices_mixin.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from collections.abc import Callable, Iterable, Sequence
2+
from collections.abc import Callable, Sequence
33
from dataclasses import dataclass, field
44

55
from umbi.datatypes import Numeric, is_numeric_a_probability
@@ -157,21 +157,23 @@ def validate(self) -> None:
157157
def new_state_choice(
158158
self,
159159
state: int,
160-
targets: Iterable[int] | None = None,
161-
target_prob: Callable[[int], Numeric | None] | None = None,
160+
targets: Sequence[int] | None = None,
161+
probs: Sequence[Numeric] | None = None,
162+
target_prob: Callable[[int], Numeric] | None = None,
162163
) -> int:
163164
"""Add a choice to the given state.
164165
:param state: source state for the new choice
165166
:param targets: optional iterable of target states for the branches of the new choice
167+
:param probs: optional probabilities for the new branches
166168
:param target_prob: optional function mapping target states to branch probabilities
167169
:return: the new choice index
168170
"""
169171
# self.state_space._check_entity(state)
170172
choice = self._new_choice()
171173
self.state_to_choices[state].append(choice)
172174
self._choice_to_state[choice] = state
173-
if targets is not None and target_prob is not None:
174-
self.new_choice_branches(choice, targets=targets, target_prob=target_prob)
175+
if targets is not None:
176+
self.new_choice_branches(choice, targets=targets, probs=probs, target_prob=target_prob)
175177
return choice
176178

177179
def remove_choice(self, choice: int) -> list[int]:
@@ -193,33 +195,56 @@ def remove_choices(self, choices: Sequence[int]) -> None:
193195
for choice in choices:
194196
self.remove_choice(choice)
195197

196-
def new_choice_branch(self, choice: int, target: int | None = None, prob: Numeric | None = None) -> int:
197-
"""Add a branch to the given choice and return it."""
198+
def new_choice_branch(
199+
self,
200+
choice: int,
201+
target: int,
202+
prob: Numeric | None = None,
203+
target_prob: Callable[[int], Numeric] | None = None,
204+
) -> int:
205+
"""Add a branch to the given choice and return it.
206+
:param choice: source choice for the new branch
207+
:param target: target state for the new branch
208+
:param prob: optional probability for the new branch
209+
:param target_prob: optional function mapping target states to branch probabilities
210+
:note: if the ATS has branch probabilities, either prob or target_prob must be provided, but not both
211+
:return: the new branch index
212+
"""
198213
self._choice_space.check_entity(choice)
199-
if target is not None:
200-
self._state_space.check_entity(target)
214+
self._state_space.check_entity(target)
201215
new_branch = self._new_branch()
202216
self._choice_to_branches[choice].append(new_branch)
203217
self._branch_to_choice[new_branch] = choice
204-
if target is not None:
205-
self._branch_to_target[new_branch] = target
218+
self._branch_to_target[new_branch] = target
219+
if prob is None and target_prob is not None:
220+
prob = target_prob(target)
206221
if prob is not None:
207222
self._branch_to_probability[new_branch] = prob
208223
return new_branch
209224

210225
def new_choice_branches(
211-
self, choice: int, targets: Iterable[int], target_prob: Callable[[int], Numeric | None]
226+
self,
227+
choice: int,
228+
targets: Sequence[int],
229+
probs: Sequence[Numeric] | None = None,
230+
target_prob: Callable[[int], Numeric] | None = None,
212231
) -> list[int]:
213232
"""Add branches to the given choice for multiple targets.
214233
:param choice: choice to add branches to
215234
:param targets: target states for the new branches
216-
:param target_prob: function mapping target states to branch probabilities
235+
:param probs: optional probabilities for the new branches
236+
:param target_prob: optional function mapping target states to branch probabilities
237+
:note: if the ATS has branch probabilities, either probs or target_prob must be provided, but not both
217238
:return: list of new branches added
218239
"""
219240
new_branches = []
220-
for target in targets:
221-
prob = target_prob(target)
222-
branch = self.new_choice_branch(choice, target=target, prob=prob)
241+
if probs is not None and len(probs) != len(targets):
242+
raise ValueError("Length of probs must match length of targets.")
243+
for target_idx, target in enumerate(targets):
244+
prob = None
245+
if probs is not None:
246+
prob = probs[target_idx]
247+
branch = self.new_choice_branch(choice, target=target, prob=prob, target_prob=target_prob)
223248
new_branches.append(branch)
224249
return new_branches
225250

0 commit comments

Comments
 (0)