def test_alphabet_unions(): # Thanks to sparse transitions it should now be possible to compute the union of FSMs # with disagreeing alphabets! a = FSM( alphabet={"a"}, states={0, 1}, initial=0, accepting={1}, transition={ 0: { "a": 1 }, }, ) b = FSM( alphabet={"b"}, states={0, 1}, initial=0, accepting={1}, transition={ 0: { "b": 1 }, }, ) assert (a | b).accepts(["a"]) assert (a | b).accepts(["b"]) assert (a & b).empty() assert (a + b).accepts(["a", "b"]) assert (a ^ b).accepts(["a"]) assert (a ^ b).accepts(["b"])
def test_bug_36(): etc1 = FSM(alphabet={unspecified}, states={0}, initial=0, accepting={0}, transition={0: { unspecified: 0 }}) etc2 = FSM(alphabet={'s', unspecified}, states={0, 1}, initial=0, accepting={1}, transition={ 0: { 's': 1 }, 1: { 's': 1, unspecified: 1 } }) both = etc1 & etc2 assert etc1.accepts(["s"]) assert etc2.accepts(["s"]) assert both.alphabet == {unspecified, "s"} assert both.accepts(["s"])
def test_invalid_fsms(): # initial state 1 is not a state try: FSM(alphabet={}, states={}, initial=1, accepting=set(), transition={}) assert False except AssertionError: assert False except Exception: pass # final state 2 not a state try: FSM(alphabet={}, states={1}, initial=1, accepting={2}, transition={}) assert False except AssertionError: assert False except Exception: pass # invalid transition for state 1, symbol "a" try: FSM(alphabet={"a"}, states={1}, initial=1, accepting=set(), transition={1: { "a": 2 }}) assert False except AssertionError: assert False except Exception: pass
def test_setacceptstate(self): f = FSM() f.addstate('freshman') f.setacceptstate('freshman') assert('freshman' in f.acceptStates) # labeling non-existant state as an accept state f = FSM() f.addstate('sophmore') self.assertRaises(ValueError,f.setacceptstate,'freshman')
def test_addbug(): # Odd bug with fsm.__add__(), exposed by "[bc]*c" int5A = FSM(alphabet={"a", "b", "c", unspecified}, states={0, 1}, initial=1, accepting={1}, transition={ 0: { unspecified: 0, "a": 0, "b": 0, "c": 0 }, 1: { unspecified: 0, "a": 0, "b": 1, "c": 1 }, }) assert int5A.accepts("") int5B = FSM(alphabet={"a", "b", "c", unspecified}, states={0, 1, 2}, initial=1, accepting={0}, transition={ 0: { unspecified: 2, "a": 2, "b": 2, "c": 2 }, 1: { unspecified: 2, "a": 2, "b": 2, "c": 0 }, 2: { unspecified: 2, "a": 2, "b": 2, "c": 2 }, }) assert int5B.accepts("c") int5C = int5A + int5B print(int5C) assert int5C.accepts("c")
def test_empty(a, b): assert not a.empty() assert not b.empty() assert FSM( alphabet={}, states={0, 1}, initial=0, accepting={1}, transition={ 0: {}, 1: {} }, ).empty() assert not FSM( alphabet={}, states={0}, initial=0, accepting={0}, transition={ 0: {} }, ).empty() assert FSM( alphabet={"a", "b"}, states={0, 1, None, 2}, initial=0, accepting={2}, transition={ 0: { "a": 1, "b": 1 }, 1: { "a": None, "b": None }, None: { "a": None, "b": None }, 2: { "a": None, "b": None }, }, ).empty()
def __init__(self, game_opts): # part of the borg pattern self.__dict__ = self.__shared_state ## the game scenes/levels self.scenes = FSM() # initialise a sample level # TODO: find a way of applying lazy initialisation # on level creation - a level should be created only # right before executed # flev = LevelFactory().create_level( # constants.SCENES['level_one'], # game_opts) flev = LevelFactory().create_level(constants.SCENES['level_one']) # set and group the scenes scenes = (Intro(game_opts), Menu(game_opts), flev) # add the scenes to the state machine for s in scenes: self.scenes.add_state(s) # enable the default state self.scenes.active_state = scenes[0]
async def game(ctx): await _join(ctx) channel = ctx.message.guild.voice_client.channel await asyncio.gather( set_mute_all(channel.members, mute=False), ctx.message.channel.send('Starting game in {}'.format(channel.name)), client.change_presence(activity=discord.Game(name='Among Us')), ) vision = Vision(static_templates, monitor) fsm = FSM( on_change_state={ 'playing': lambda: asyncio.run_coroutine_threadsafe( set_mute_all(channel.members), main_loop), 'voting': lambda: asyncio.run_coroutine_threadsafe( set_mute_all(channel.members, mute=False), main_loop) }) controller = Controller(fsm, vision) async def step(): controller.step() if not should_stop: await asyncio.sleep(1) await step() global should_stop should_stop = False await step()
def test_accepts_basic_2(self): a = FSM() a.setstartstate('q1') a.addstate('q2') a.addstate('q3') a.addstate('q4') a.addstate('q5') a.addstate('q6') a.setacceptstate('q2') a.setacceptstate('q5') a.addtransition('q1','q2','1') a.addtransition('q2','q1','0') a.addtransition('q1','q1','0') a.addtransition('q2','q3','0') a.addtransition('q3','q4','0') a.addtransition('q4','q5','0') a.addtransition('q5','q6','0') a.addtransition('q6','q3','1') self.assertFalse(a.accepts('0010')) # False self.assertFalse(a.accepts('10')) # False self.assertFalse(a.accepts('100')) # False self.assertTrue(a.accepts('1000')) # True self.assertTrue(a.accepts('0101')) # True self.assertTrue(a.accepts('100001')) # True a.addtransition('q3','q2','0') self.assertTrue(a.accepts('1000010')) # True self.assertTrue(a.accepts('101000001000')) # True self.assertFalse(a.accepts('1010000011')) # This depends on the case of invalid alphabets
def test_difference(a, b): aorb = FSM( alphabet={"a", "b"}, states={0, 1, None}, initial=0, accepting={1}, transition={ 0: { "a": 1, "b": 1 }, 1: { "a": None, "b": None }, None: { "a": None, "b": None }, }, ) assert list((a ^ a).strings()) == [] assert list((b ^ b).strings()) == [] assert list((a ^ b).strings()) == [["a"], ["b"]] assert list((aorb ^ a).strings()) == [["b"]]
def test_star_advanced(): # This is (a*ba)*. Naively connecting the final states to the initial state # gives the incorrect result here. starred = FSM(alphabet={"a", "b"}, states={0, 1, 2, "oblivion"}, initial=0, accepting={2}, transition={ 0: { "a": 0, "b": 1 }, 1: { "a": 2, "b": "oblivion" }, 2: { "a": "oblivion", "b": "oblivion" }, "oblivion": { "a": "oblivion", "b": "oblivion" }, }).star() assert starred.alphabet == frozenset(["a", "b"]) assert starred.accepts("") assert not starred.accepts("a") assert not starred.accepts("b") assert not starred.accepts("aa") assert starred.accepts("ba") assert starred.accepts("aba") assert starred.accepts("aaba") assert not starred.accepts("aabb") assert starred.accepts("abababa")
def test_crawl_reduction(): # this is "0*1" in heavy disguise. crawl should resolve this duplication # Notice how states 2 and 3 behave identically. When resolved together, # states 1 and 2&3 also behave identically, so they, too should be resolved # (this is impossible to spot before 2 and 3 have been combined). # Finally, the oblivion state should be omitted. merged = FSM(alphabet={"0", "1"}, states={1, 2, 3, 4, "oblivion"}, initial=1, accepting={4}, transition={ 1: { "0": 2, "1": 4 }, 2: { "0": 3, "1": 4 }, 3: { "0": 3, "1": 4 }, 4: { "0": "oblivion", "1": "oblivion" }, "oblivion": { "0": "oblivion", "1": "oblivion" }, }).reduce() assert len(merged.states) == 2
def main(self): """ Main program method """ # $ - numbers [0-9] # ¤ - LED IDs [0-5] # @ - any character rules = [ Rule("init", "read", "@", "A1"), Rule("read", "read", "$", "A2"), Rule("read", "verify", "*", "A3"), Rule("read", "init", "@", "A4"), Rule("verify", "active", "Y", "A5"), Rule("verify", "init", "N"), Rule("active", "read-2", "*"), Rule("active", "duration-entry", "¤", "A9"), # WARNING: only 0-5 work, 6-9 crash Rule("active", "logout", "#"), Rule("read-2", "read-2", "$", "A2"), Rule("read-2", "read-3", "*", "A7"), Rule("read-2", "active", "@", "A6"), Rule("read-3", "read-3", "$", "A2"), Rule("read-3", "active", "*", "A8"), Rule("read-3", "active", "@", "A6"), Rule("duration-entry", "duration-entry", "$", "A10"), Rule("duration-entry", "active", "*", "A11"), Rule("logout", "init", "#", "A12"), Rule("logout", "active", "@"), ] fsm = FSM() fsm.set_rules(rules) fsm.run()
def build(self, **actions): """Construct an FSM from a parsed fsm description file. Keyword arguments: **actions -- each action routine callable """ states = {} for state in self.states.values(): s = FSM.STATE( name=state.name, on_enter=actions[state.enter] if state.enter else None, on_exit=actions[state.exit] if state.exit else None, ) states[s.name] = s for event in state.events.values(): e = FSM.EVENT( name=event.name, actions=[actions[n] for n in event.actions], next_state=event.next_state, ) s.events[e.name] = e for state in states.values(): for event in state.events.values(): if event.next_state: event.next_state = states[event.next_state] fsm = FSM.FSM(states.values()) fsm.state = self.first_state fsm.context = self.context fsm.exception = self.exception return fsm
def test_accepts_basic(self): a = FSM() a.setstartstate('q1') a.addstate('q2') a.setacceptstate('q2') a.addtransition('q1','q2','1') a.addtransition('q2','q1','0') self.assertTrue(a.accepts('1')) # True self.assertFalse(a.accepts('10')) # False self.assertTrue(a.accepts('101')) # True self.assertFalse(a.accepts('1010')) # False self.assertFalse(a.accepts('1010101110001110101')) # This depends on how you handle invalid letters self.assertFalse(a.accepts('10101010101010101010')) # False a.addstate('q3') a.addtransition('q2','q3','1') a.addtransition('q3','q1','1') self.assertFalse(a.accepts('11')) # False self.assertTrue(a.accepts('1111')) # True self.assertFalse(a.accepts('10101111011')) # False a.addtransition('q3','q2','1') self.assertTrue(a.accepts('111')) # True - this fails bc this is deterministic self.assertFalse(a.accepts('')) # False self.assertFalse(a.accepts('14')) # # This depends on how you handle invalid letters self.assertTrue(a.accepts('1')) # True
def test_constuctor(self): f = FSM() assert(type(f) == FSM) assert(f.currentState is None) assert(len(f.acceptStates) == 0) assert(f.startState is None) assert(len(f.states) == 0)
def test_setstartstate(self): # adding state then declaring startstate f = FSM() f.addstate('freshman') f.addstate('sophmore') f.addstate('junior') f.addstate('senior') f.setstartstate('freshman') assert(f.startState.state == 'freshman') assert(f.startState.state in f.states) # adding and declaring startstate at once f = FSM() f.setstartstate('freshman') assert(f.startState.state == 'freshman') assert(f.startState.state in f.states)
def test_accepts_basic_3(self): f = FSM() f.addstate('freshman') f.addstate('sophmore') f.addstate('junior') f.addstate('senior') f.setstartstate('freshman') f.addtransition('freshman','freshman','F') f.addtransition('sophmore','sophmore','F') f.addtransition('junior','junior','F') f.addtransition('senior','senior','F') f.addtransition('freshman','sophmore','A') f.addtransition('sophmore','junior','A') f.addtransition('junior','senior','A') f.addtransition('senior','freshman','F') f.addtransition('junior','freshman','F') f.addtransition('sophmore','freshman','F') f.setacceptstate('senior') self.assertTrue(f.accepts('AAA')) # True self.assertTrue(f.accepts('AAAF')) # True self.assertTrue(f.accepts('AAAFAAA')) # True self.assertTrue(f.accepts('FAFAAFAAA')) # True self.assertTrue(f.accepts('FAFAAFA')) # True self.assertTrue(f.accepts('AFAA')) self.assertFalse(f.accepts('AA')) self.assertFalse(f.accepts('FAFF')) self.assertFalse(f.accepts('AAAA')) self.assertFalse(f.accepts('AFFFFF')) self.assertFalse(f.accepts('AFAAFAFA'))
def dangie_fsm(functions): from fsm import FSM fsm = FSM() for function in functions: fsm = function.add_to_fsm(fsm) fsm = fsm.make_dangie_ready() return fsm
def test_oblivion_crawl(a): # When crawling a new FSM, we should avoid generating an oblivion state. # `abc` has no oblivion state... all the results should not as well! abc = FSM(alphabet={"a", "b", "c"}, states={0, 1, 2, 3}, initial=0, accepting={3}, transition={ 0: { "a": 1 }, 1: { "b": 2 }, 2: { "c": 3 }, }) assert len((abc + abc).states) == 7 assert len(abc.star().reduce().states) == 3 assert len((abc * 3).states) == 10 assert len(reversed(abc).states) == 4 assert len((abc | abc).states) == 4 assert len((abc & abc).states) == 4 assert len((abc ^ abc).reduce().states) == 1 assert len((abc - abc).reduce().states) == 1
def parse_inventory(file): fsm = FSM(_S, _S.TOP, [_S.TOP], machine) fsm.reset() fsm.data = {'current_item': {}, 'relic': [], 'morality': [], 'archeo': []} #fsm.tracing(True) fsm.parse(file) return fsm.data['relic'], fsm.data['archeo'], fsm.data['morality']
def test_sl_to_fsm_2(self): """ Checks if a 2-SL grammar translates to FSM correctly. """ f = FSM(initial=">", final="<") grammar = [(">", "a"), ("b", "a"), ("a", "b"), ("b", "<")] f.sl_to_fsm(grammar) tr = {((">", ), "a", ("a", )), (("b", ), "a", ("a", )), (("a", ), "b", ("b", )), (("b", ), "<", ("<", ))} self.assertTrue(set(f.transitions) == tr)
def test_accepts_noStates(self): f = FSM() # testing accepts without given a startstate self.assertRaises(ValueError,f.accepts,'10121') # given non-existent states f.setstartstate("pie") self.assertRaises(KeyError,f.addtransition,'fail','this','1') self.assertFalse(f.accepts("thereisnothing"))
def parse_enchants(file): fsm = FSM(_S, _S.TOP, [_S.TOP], machine) fsm.reset() fsm.data = {'shortcuts': {}, 'enchants': [], 'temp': None} #fsm.tracing(True) data = fsm.parse(file) return data['shortcuts'], data['enchants']
def test_addstate(self): a = FSM() a.addstate('q1') a.addstate('q2') a.addstate('q3') a.addstate('q4') a.addstate('q5') a.addstate('q6') assert(len(a.states) == 6)
def test_trim_fsm_2(self): f = FSM(initial=">", final="<") f.transitions = [((">", ), "a", ("a", )), (("b", ), "a", ("a", )), (("a", ), "b", ("b", )), (("b", ), "<", ("<", )), ((">", ), "c", ("c", )), (("d", ), "<", ("<", ))] goal = {((">", ), "a", ("a", )), (("b", ), "a", ("a", )), (("a", ), "b", ("b", )), (("b", ), "<", ("<", ))} f.trim_fsm() self.assertTrue(set(f.transitions) == goal)
def explain_nodered(): fsm = FSM({'browser', 'node-red', 'spi-din', 'sqlite', 'db manager'}) fsm.transition('browser', 'node-red', 'http request') fsm.transition('node-red', 'browser', 'http request') fsm.transition('node-red', 'node-red', 'flow control and javascript functions') fsm.transition('node-red', 'spi-din', 'widgetlords node') fsm.transition('node-red', 'sqlite', 'sqlite node') fsm.transition('db manager', 'sqlite', 'manual modificatin') fsm.save(name='nodered_relays_explanation')
def __init__(self): # part of the borg pattern self.__dict__ = self.__shared_state # initialize the state State.__init__(self, constants.SCENES['level_one']) # the 1st level states self.states = FSM() # self.game_opts = game_opts self.states.active_state = None
def explain(): fsm = FSM({ 'browser', 'flask', 'views', 'domain', 'drivers', 'models', 'sqlalchemy', 'sqlite', 'jinja', 'red = performing action', 'green = rendering page', }) fsm.fail('browser', 'flask', 'http requests') fsm.fail('flask', 'views', 'url routing') fsm.fail('views', 'domain', 'domain commands') fsm.fail('domain', 'models', 'set model state') fsm.fail('domain', 'drivers', 'set hardware state') fsm.fail( 'models', 'sqlalchemy', 'manage db session', ) fsm.fail( 'sqlalchemy', 'sqlite', 'SQL', ) fsm.success('views', 'models', 'get model state') fsm.success( 'models', 'sqlalchemy', 'query', ) fsm.success( 'sqlalchemy', 'sqlite', 'SQL', ) fsm.success( 'sqlite', 'sqlalchemy', 'rows', ) fsm.success( 'sqlalchemy', 'models', 'models', ) fsm.success('models', 'views', 'models') fsm.success('views', 'jinja', 'templating context') fsm.success('jinja', 'flask', 'html') fsm.success('flask', 'browser', 'http response') fsm.save(name='agua_relays_explanation')
def __init__(self): # Create a State Machine object self.__my_fsm = FSM() # Create a Sender and Receiver Driver object self.__sd = Sender_Driver(self.__my_fsm) self.__rd = Receiver_Driver(self.__my_fsm) # Create a GUI object self.__my_gui = SerialGUI(self.__my_fsm, self.__sd, self.__rd) self.__my_gui.window.mainloop()