I am using pytransitions and have come across the need to have several states which are unrelated with others, and would make much sense to model using a non deterministic state machine, which is mathematically equivalent.
I would like something like the following
from transitions import Machine
from transitions import EventData
class Matter(object):
def __init__(self):
transitions1 = [
{'trigger': 'heat', 'source': 'solid', 'dest': 'liquid'},
{'trigger': 'heat', 'source': 'liquid', 'dest': 'gas'},
{'trigger': 'cool', 'source': 'gas', 'dest': 'liquid'},
{'trigger': 'cool', 'source': 'liquid', 'dest': 'solid'}
]
transitions2 = [
{'trigger': 'turn_on', 'source': 'off', 'dest': 'on'},
{'trigger': 'turn_off', 'source': 'on', 'dest': 'off'},
]
self.machine = Machine(
model=self,
states=[['solid', 'liquid', 'gas'], ['on', 'off']],
transitions=[transitions1, transitions2],
initial=['solid', 'off'],
send_event=True
)
def on_enter_gas(self, event: EventData):
print(f"entering gas from {event.transition.source}")
def on_enter_liquid(self, event: EventData):
print(f"entering liquid from {event.transition.source}")
def on_enter_solid(self, event: EventData):
print(f"entering solid from {event.transition.source}")
def on_enter_on(self, event: EventData):
print(f"entering on from {event.transition.source}")
def on_enter_off(self, event: EventData):
print(f"entering off from {event.transition.source}")
I could define a new set of states to be states=itertools.product(states1, states2) and then define all the transitions as the equivalence theorem shows.
I was wondering if this behavior is supported in the library and if so, how to achieve it.
I have more than just 2 sets of (mostly) independent states. Really, I have a bunch of toggles that occasionally have interactions, but mostly are independent.
for me this sounds like what you are looking for is not necessarily non-determinism but hierarchical/compound states and concurrency/parallelism.
You could make use of transitions Hierarchical State Machine extension that also features concurrency:
However, HSMs are significantly more complex than simple
Machines. The documentation mentions several restrictions considering naming conventions and nesting/initialization configurations that need to be followed.This is why I usually try to find the simplest solution for my FSM architecture. Right now your nesting is rather flat and it could also be achieved with a set of models and
Machines. The 'rulebook' approach of transitions makes it rather easy to manage multiple models in different states with just one machine and its 'dispatch' method:From your comments:
This could be solved with HSMs by defining
heatevents only on source stateson_*. However, if you have many of these dependent variables, the nesting could become quite complex. Instead you could add references to the other machine'sis_<state>convenience functions to the condition list of all related transitions. This can be done after initialization in case bootstrapping is an issue: