python - 使用 PyTransitions 的非确定性状态机?

标签 python state-machine automaton pytransitions

我正在使用pytransitions并且遇到了需要拥有几个与其他状态无关的状态,并且使用 non deterministic state machine 进行建模非常有意义,这在数学上是等价的。

我想要类似下面的内容

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}")

我可以将一组新的状态定义为 states=itertools.product(states1, states2),然后定义所有转换,如等价定理所示。

我想知道库是否支持这种行为,如果支持,如何实现。

我有不止 2 组(大部分)独立的状态。确实,我有一堆偶尔会交互的开关,但大多数都是独立的。

最佳答案

... to have several states which are unrelated with others, and would make much sense to model using a non deterministic state machine

对我来说,这听起来像是您正在寻找的不一定是非确定性的,而是 hierarchical/compound州和concurrency/parallelism .

您可以利用过渡 Hierarchical State Machine还具有并发功能的扩展:

from transitions.extensions import HierarchicalMachine

states1 = ['solid', 'liquid', 'gas']
states2 = ['on', 'off']

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'},
]

combined_states = [
    {"name": "running", "parallel":
        [
            dict(name="component1", states=states1, transitions=transitions1, initial=states1[0]),
            dict(name="component2", states=states2, transitions=transitions2, initial=states2[0])
        ]
    }
]

m = HierarchicalMachine(states=combined_states, auto_transitions=False, initial="running")
print(m.state)  # >>> ['running_component1_solid', 'running_component2_on']
m.turn_off()
print(m.state)  # >>> ['running_component1_solid', 'running_component2_off']

但是,HSM 比简单的复杂得多 Machines 。该文档提到了一些考虑到需要遵循的命名约定和嵌套/初始化配置的限制。

这就是为什么我通常尝试为我的 FSM 架构找到最简单的解决方案。现在,您的嵌套相当平坦,也可以通过一组模型和 Machines 来实现。 。转换的“规则手册”方法使得仅用一台机器及其"dispatch"方法就可以轻松管理不同状态下的多个模型:

from transitions import Machine


class Model:
    pass


class MultiMachine(Machine):

    def __init__(self, configurations):
        # Initialize the machine blank, no states, no transitions and
        # no initial states. Disable auto_transitions since there shouldn't
        # be the possibility to transition e.g. from 'on' to 'liquid'.
        # Furthermore, ignore_invalid_triggers so that events not considered
        # by a model will not throw an exception.
        super().__init__(model=None, states=[], transitions=[], initial=None, auto_transitions=False,
                         ignore_invalid_triggers=True)
        # create a model for each configuration
        for states, transitions, initial in configurations:
            self.add_states(states)
            self.add_transitions(transitions)
            self.add_model(Model(), initial=initial)

    @property
    def state(self):
        return [model.state for model in self.models]


m = MultiMachine([(states1, transitions1, 'solid'), (states2, transitions2, 'off')])
assert m.state == ['solid', 'off']
m.dispatch("turn_on")
assert m.state == ['solid', 'on']
m.dispatch("heat")
assert m.state == ['liquid', 'on']

来自您的评论:

How can I add a conditional transition in one sub-machine, based on the state in another? For example, heat should only make solid into gas in case of on? [...] HSMs, maybe it is better in this case.

这可以通过定义 heat 使用 HSM 来解决仅在源状态上发生的事件 on_* 。但是,如果有许多此类因变量,则嵌套可能会变得相当复杂。相反,您可以添加对另一台机器的 is_<state> 的引用所有相关转换的条件列表的便利函数。这可以在初始化后完成,以防引导出现问题:

from transitions import Machine
from transitions.core import Condition

states1 = ['solid', 'liquid', 'gas']
states2 = ['off', 'on']

m1 = Machine(states=states1, initial=states1[0],
             transitions=[{'trigger': 'heat', 'source': 'solid', 'dest': 'liquid'},
                          {'trigger': 'heat', 'source': 'liquid', 'dest': 'gas'},
                          {'trigger': 'cool', 'source': 'gas', 'dest': 'liquid'},
                          {'trigger': 'cool', 'source': 'liquid', 'dest': 'solid'}])
m2 = Machine(states=states2, initial=states2[0],
             transitions=[{'trigger': 'turn_on', 'source': 'off', 'dest': 'on'},
                          {'trigger': 'turn_off', 'source': 'on', 'dest': 'off'}])

# get all heat transitions and add the condition that they may only be valid when m2.is_on returns True
for trans in m1.get_transitions("heat"):
    trans.conditions.append(Condition(func=m2.is_on))
    # if you want to add an 'unless' statement pass `target=False`
    # to the condition. e.g. "heat unless m2 is off"
    # trans.conditions.append(Condition(func=m2.is_off, target=False))

assert m1.is_solid()
assert m2.is_off()
assert not m1.heat()
assert m1.is_solid()
assert m2.turn_on()
assert m1.heat()
assert m1.is_liquid()

关于python - 使用 PyTransitions 的非确定性状态机?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68336228/

相关文章:

状态机的 C++ 代码

c# - 虚拟方法可以中止覆盖它的抽象方法的执行吗?

prolog - 如何卡住变量列表的目标?

isabelle - 多态类型的存在证明

python - 在 python 中获取新数据框中的员工代码计数

python - 将 any 与 QuerySet 一起使用是否不是最佳选择?

python - 如何根据环境从我的 settings.py DATABASES 数组中激活数据库设置?

python - 在 Django 查询集中过滤不存在​​的 GenericForeignKey 对象

QT : Using State Machine for UI interactions?

context-free-grammar - 对于上下文无关语法,如何将其转换为等效的下推自动机?