add examples
This commit is contained in:
parent
8504ba52f6
commit
42757ddc4f
35 changed files with 1104 additions and 609 deletions
|
|
@ -10,12 +10,10 @@ from concrete_syntax.textual_od.renderer import render_od
|
|||
from transformation.cloner import clone_od
|
||||
from api.od import ODAPI
|
||||
|
||||
class DecisionMaker:
|
||||
@abc.abstractmethod
|
||||
def __call__(self, actions):
|
||||
pass
|
||||
from util.simulator import MinimalSimulator, DecisionMaker, RandomDecisionMaker, InteractiveDecisionMaker
|
||||
|
||||
class Simulator:
|
||||
|
||||
class Simulator(MinimalSimulator):
|
||||
def __init__(self,
|
||||
action_generator,
|
||||
decision_maker: DecisionMaker,
|
||||
|
|
@ -24,51 +22,26 @@ class Simulator:
|
|||
verbose=True,
|
||||
renderer=lambda od: render_od(od.state, od.m, od.mm),
|
||||
):
|
||||
self.action_generator = action_generator
|
||||
self.decision_maker = decision_maker
|
||||
self.termination_condition = termination_condition
|
||||
super().__init__(
|
||||
action_generator=action_generator,
|
||||
decision_maker=decision_maker,
|
||||
termination_condition=lambda od: self.check_render_termination_condition(od),
|
||||
verbose=verbose,
|
||||
)
|
||||
self.check_conformance = check_conformance
|
||||
self.verbose = verbose
|
||||
self.actual_termination_condition = termination_condition
|
||||
self.renderer = renderer
|
||||
|
||||
def __print(self, *args):
|
||||
if self.verbose:
|
||||
print(*args)
|
||||
|
||||
# Run simulation until termination condition satisfied
|
||||
def run(self, od: ODAPI):
|
||||
self.__print("Start simulation")
|
||||
self.__print(f"Decision maker: {self.decision_maker}")
|
||||
step_counter = 0
|
||||
while True:
|
||||
self.__print("--------------")
|
||||
self.__print(indent(self.renderer(od), 4))
|
||||
self.__print("--------------")
|
||||
|
||||
termination_reason = self.termination_condition(od)
|
||||
if termination_reason != None:
|
||||
self.__print(f"Termination condition satisfied.\nReason: {termination_reason}.")
|
||||
break
|
||||
|
||||
actions = self.action_generator(od)
|
||||
|
||||
chosen_action = self.decision_maker(actions)
|
||||
|
||||
if chosen_action == None:
|
||||
self.__print(f"No enabled actions.")
|
||||
break
|
||||
|
||||
(od, msgs) = chosen_action()
|
||||
self.__print(indent('\n'.join(f"▸ {msg}" for msg in msgs), 2))
|
||||
|
||||
step_counter += 1
|
||||
|
||||
if self.check_conformance:
|
||||
self.__print()
|
||||
conf = Conformance(od.state, od.m, od.mm)
|
||||
self.__print(render_conformance_check_result(conf.check_nominal()))
|
||||
self.__print(f"Executed {step_counter} steps.")
|
||||
return od
|
||||
def check_render_termination_condition(self, od):
|
||||
# A termination condition checker that also renders the model, and performs conformance check
|
||||
self._print("--------------")
|
||||
self._print(indent(self.renderer(od), 2))
|
||||
self._print("--------------")
|
||||
if self.check_conformance:
|
||||
conf = Conformance(od.state, od.m, od.mm)
|
||||
self._print(render_conformance_check_result(conf.check_nominal()))
|
||||
self._print()
|
||||
return self.actual_termination_condition(od)
|
||||
|
||||
def make_actions_pure(actions, od):
|
||||
# Copy model before modifying it
|
||||
|
|
@ -81,65 +54,17 @@ def make_actions_pure(actions, od):
|
|||
for descr, action in actions:
|
||||
yield (descr, functools.partial(exec_pure, action, od))
|
||||
|
||||
|
||||
def filter_valid_actions(pure_actions):
|
||||
result = {}
|
||||
def make_tuple(new_od, msgs):
|
||||
return (new_od, msgs)
|
||||
for name, callback in pure_actions:
|
||||
print(f"attempt '{name}' ...", end='\r')
|
||||
# print(f"attempt '{name}' ...", end='\r')
|
||||
(new_od, msgs) = callback()
|
||||
conf = Conformance(new_od.state, new_od.m, new_od.mm)
|
||||
errors = conf.check_nominal()
|
||||
# erase current line:
|
||||
print(" ", end='\r')
|
||||
# print(" ", end='\r')
|
||||
if len(errors) == 0:
|
||||
# updated RT-M is conform, we have a valid action:
|
||||
yield (name, functools.partial(make_tuple, new_od, msgs))
|
||||
|
||||
|
||||
class RandomDecisionMaker(DecisionMaker):
|
||||
def __init__(self, seed=0, verbose=True):
|
||||
self.seed = seed
|
||||
self.r = random.Random(seed)
|
||||
|
||||
def __str__(self):
|
||||
return f"RandomDecisionMaker(seed={self.seed})"
|
||||
|
||||
def __call__(self, actions):
|
||||
arr = [action for descr, action in actions]
|
||||
i = math.floor(self.r.random()*len(arr))
|
||||
return arr[i]
|
||||
|
||||
class InteractiveDecisionMaker(DecisionMaker):
|
||||
# auto_proceed: whether to prompt if there is only one enabled action
|
||||
def __init__(self, msg="Select action:", auto_proceed=False):
|
||||
self.msg = msg
|
||||
self.auto_proceed = auto_proceed
|
||||
|
||||
def __str__(self):
|
||||
return f"InteractiveDecisionMaker()"
|
||||
|
||||
def __call__(self, actions):
|
||||
arr = []
|
||||
for i, (key, result) in enumerate(actions):
|
||||
print(f" {i}. {key}")
|
||||
arr.append(result)
|
||||
if len(arr) == 0:
|
||||
return
|
||||
if len(arr) == 1 and self.auto_proceed:
|
||||
return arr[0]
|
||||
|
||||
def __choose():
|
||||
sys.stdout.write(f"{self.msg} ")
|
||||
try:
|
||||
raw = input()
|
||||
choice = int(raw) # may raise ValueError
|
||||
if choice >= 0 and choice < len(arr):
|
||||
return arr[choice]
|
||||
except ValueError:
|
||||
pass
|
||||
print("Invalid option")
|
||||
return __choose()
|
||||
|
||||
return __choose()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue