def test_alphabet_unions(): # Thanks to sparse maps it should now be possible to compute the union of FSMs # with disagreeing alphabets! a = fsm( alphabet={"a"}, states={0, 1}, initial=0, finals={1}, map={ 0: { "a": 1 }, }, ) b = fsm( alphabet={"b"}, states={0, 1}, initial=0, finals={1}, map={ 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_empty(a, b): assert not a.empty() assert not b.empty() assert fsm( alphabet = {}, states = {0, 1}, initial = 0, finals = {1}, map = {0:{}, 1:{}}, ).empty() assert not fsm( alphabet = {}, states = {0}, initial = 0, finals = {0}, map = {0:{}}, ).empty() assert fsm( alphabet = {"a", "b"}, states = {0, 1, None, 2}, initial = 0, finals = {2}, map = { 0 : {"a" : 1 , "b" : 1 }, 1 : {"a" : None, "b" : None}, None : {"a" : None, "b" : None}, 2 : {"a" : None, "b" : None}, }, ).empty()
def test_alphabet_unions(): # Thanks to sparse maps it should now be possible to compute the union of FSMs # with disagreeing alphabets! a = fsm( alphabet = {"a"}, states = {0, 1}, initial = 0, finals = {1}, map = { 0 : {"a" : 1}, }, ) b = fsm( alphabet = {"b"}, states = {0, 1}, initial = 0, finals = {1}, map = { 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={anything_else}, states={0}, initial=0, finals={0}, map={0: { anything_else: 0 }}) etc2 = fsm(alphabet={'s', anything_else}, states={0, 1}, initial=0, finals={1}, map={ 0: { 's': 1 }, 1: { 's': 1, anything_else: 1 } }) both = etc1 & etc2 assert etc1.accepts(["s"]) assert etc2.accepts(["s"]) assert both.alphabet == {anything_else, "s"} assert both.accepts(["s"])
def test_addbug(): # Odd bug with fsm.__add__(), exposed by "[bc]*c" int5A = fsm( alphabet = {"a", "b", "c", anything_else}, states = {0, 1}, initial = 1, finals = {1}, map = { 0: {anything_else: 0, "a": 0, "b": 0, "c": 0}, 1: {anything_else: 0, "a": 0, "b": 1, "c": 1}, } ) assert int5A.accepts("") int5B = fsm( alphabet = {"a", "b", "c", anything_else}, states = {0, 1, 2}, initial = 1, finals = {0}, map = { 0: {anything_else: 2, "a": 2, "b": 2, "c": 2}, 1: {anything_else: 2, "a": 2, "b": 2, "c": 0}, 2: {anything_else: 2, "a": 2, "b": 2, "c": 2}, } ) assert int5B.accepts("c") int5C = int5A + int5B assert int5C.accepts("c")
def test_addbug(): # Odd bug with fsm.__add__(), exposed by "[bc]*c" int5A = fsm(alphabet={"a", "b", "c", anything_else}, states={0, 1}, initial=1, finals={1}, map={ 0: { anything_else: 0, "a": 0, "b": 0, "c": 0 }, 1: { anything_else: 0, "a": 0, "b": 1, "c": 1 }, }) assert int5A.accepts("") int5B = fsm(alphabet={"a", "b", "c", anything_else}, states={0, 1, 2}, initial=1, finals={0}, map={ 0: { anything_else: 2, "a": 2, "b": 2, "c": 2 }, 1: { anything_else: 2, "a": 2, "b": 2, "c": 0 }, 2: { anything_else: 2, "a": 2, "b": 2, "c": 2 }, }) assert int5B.accepts("c") int5C = int5A + int5B 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, finals={1}, map={ 0: {}, 1: {} }, ).empty() assert not fsm( alphabet={}, states={0}, initial=0, finals={0}, map={ 0: {} }, ).empty() assert fsm( alphabet={"a", "b"}, states={0, 1, None, 2}, initial=0, finals={2}, map={ 0: { "a": 1, "b": 1 }, 1: { "a": None, "b": None }, None: { "a": None, "b": None }, 2: { "a": None, "b": None }, }, ).empty()
def internal_mutation_fsm(ind, indpb, new_layer_pb, config): num_layers = len(ind.net_struct) for pos_layer in range(0, num_layers): parameters_dict = ind.net_struct[pos_layer].parameters layer_type = ind.net_struct[pos_layer].type for parameter in parameters_dict.keys(): # TODO QUITA LA ÑAPA Alex if random.random( ) < indpb and parameter != 'input_shape' and parameter != 'units': parameters_dict[parameter] = generate_random_layer_parameter( parameter, layer_type, config) if random.random() < new_layer_pb: # Where to insert new layers? position = random.choice(range(0, len(ind.net_struct) - 1)) init_type = ind.net_struct[position].type end_type = ind.net_struct[position + 1].type the_map = config.fsm['map'] # Forces the FSM to start at the same type as the selected gen the_map['inicial'] = {init_type: init_type} state_machine = fsm(alphabet=set(config.fsm['alphabet']), states=set(config.fsm['states']), initial="inicial", finals={end_type}, map=the_map) # Computes sequences [init_type, ..., end_type] with length between 3 and 5 in order to insert 1 to 3 new layers candidates = list( itertools.takewhile( lambda c: len(c) <= 5, itertools.dropwhile(lambda l: len(l) < 3, state_machine.strings()))) first_layers = list(set([b[0] for b in candidates])) candidates = [ random.choice([z for z in candidates if z[0] == first_layers[l]]) for l in range(len(first_layers)) ] # Sizes of the candidates sizes = list(set(map(len, candidates))) max_layers = config.global_parameters['number_layers']['values'][1] sizes = list( filter(lambda s: s <= max_layers - len(ind.net_struct), sizes)) if sizes: # Chooses a size of candidate... random_size = random.choice(sizes) candidates_size = list( filter(lambda c: len(c) == random_size, candidates)) if candidates_size: # ... and selects it as the layers to be inserted candidate = random.choice(candidates_size) candidate = list(map(lambda lt: Layer([lt], config), candidate)) # Updates the individual with new layers ind.net_struct = ind.net_struct[:position + 1] + candidate[ 1:-1] + ind.net_struct[position + 1:] ind.global_attributes.number_layers = len(ind.net_struct) return ind
def test_base_N(): # Machine accepts only numbers in selected base (e.g. 2, 10) that are # divisible by N (e.g. 3, 7). # "0" alone is acceptable, but leading zeroes (e.g. "00", "07") are not base = 2 N = 3 assert base <= 10 divN = from_fsm(fsm.fsm( alphabet = set(str(i) for i in range(base)), states = set(range(N)) | {"initial", "zero", None}, initial = "initial", finals = {"zero", 0}, map = dict( [ ("initial", dict([(str(j), j % N) for j in range(1, base)] + [("0", "zero")])), ("zero" , dict([(str(j), None ) for j in range( base)] )), (None , dict([(str(j), None ) for j in range( base)] )), ] + [ (i , dict([(str(j), (i * base + j) % N) for j in range( base)] )) for i in range(N) ] ), )) gen = divN.strings() a = next(gen) assert a == "0" for i in range(7): b = next(gen) assert int(a, base) + N == int(b, base) a = b
def test_binary_3(): # Binary numbers divisible by 3. # Disallows the empty string # Allows "0" on its own, but not leading zeroes. div3 = from_fsm(fsm.fsm( alphabet = {"0", "1"}, states = {"initial", "zero", 0, 1, 2, None}, initial = "initial", finals = {"zero", 0}, map = { "initial" : {"0" : "zero", "1" : 1 }, "zero" : {"0" : None , "1" : None}, 0 : {"0" : 0 , "1" : 1 }, 1 : {"0" : 2 , "1" : 0 }, 2 : {"0" : 1 , "1" : 2 }, None : {"0" : None , "1" : None}, }, )) assert str(div3) == "0|1(01*0|10*1)*10*" gen = div3.strings() assert next(gen) == "0" assert next(gen) == "11" assert next(gen) == "110" assert next(gen) == "1001" assert next(gen) == "1100"
def test_difference(a, b): aorb = fsm( alphabet={"a", "b"}, states={0, 1, None}, initial=0, finals={1}, map={ 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 fsm(self, alphabet=None): from greenery.fsm import fsm if alphabet is None: alphabet = self.alphabet() # 0 is initial, 1 is final, 2 is oblivion # If negated, make a singular FSM accepting any other characters if self.negated: map = { 0: dict([(symbol, 2 if symbol in self.chars else 1) for symbol in alphabet]), 1: dict([(symbol, 2) for symbol in alphabet]), 2: dict([(symbol, 2) for symbol in alphabet]), } # If normal, make a singular FSM accepting only these characters else: map = { 0: dict([(symbol, 1 if symbol in self.chars else 2) for symbol in alphabet]), 1: dict([(symbol, 2) for symbol in alphabet]), 2: dict([(symbol, 2) for symbol in alphabet]), } return fsm( alphabet = alphabet, states = set([0, 1, 2]), initial = 0, finals = set([1]), map = map, )
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, finals={4}, map={ 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 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, finals={3}, map={ 0: { "a": 1 }, 1: { "b": 2 }, 2: { "c": 3 }, }) assert len((abc + abc).states) == 7 assert len(abc.star().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).states) == 1 assert len((abc - abc).states) == 1
def test_even_star_bug(): # Bug fix. This is a(a{2})* (i.e. accepts an odd number of "a" chars in a # row), but when from_fsm() is called, the result is "a+". Turned out to be # a fault in the lego.multiplier.__mul__() routine elesscomplex = fsm.fsm( alphabet = {"a"}, states = {0, 1}, initial = 0, finals = {1}, map = { 0 : {"a" : 1}, 1 : {"a" : 0}, }, ) assert not elesscomplex.accepts("") assert elesscomplex.accepts("a") assert not elesscomplex.accepts("aa") assert elesscomplex.accepts("aaa") elesscomplex = from_fsm(elesscomplex) assert str(elesscomplex) in {"a(aa)*", "(aa)*a"} elesscomplex = elesscomplex.to_fsm() assert not elesscomplex.accepts("") assert elesscomplex.accepts("a") assert not elesscomplex.accepts("aa") assert elesscomplex.accepts("aaa") gen = elesscomplex.strings() assert next(gen) == ["a"] assert next(gen) == ["a", "a", "a"] assert next(gen) == ["a", "a", "a", "a", "a"] assert next(gen) == ["a", "a", "a", "a", "a", "a", "a"]
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, finals = {2}, map = { 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_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, finals={2}, map={ 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_dead_default(): ''' You may now omit a transition, or even an entire state, from the map. This affects every usage of `fsm.map`. ''' blockquote = fsm( alphabet = {"/", "*", anything_else}, states = {0, 1, 2, 3, 4, 5}, initial = 0, finals = {4}, map = { 0 : {"/" : 1}, 1 : {"*" : 2}, 2 : {"/" : 2, anything_else : 2, "*" : 3}, 3 : {"/" : 4, anything_else : 2, "*" : 3}, } ) assert blockquote.accepts(["/", "*", "whatever", "*", "/"]) assert not blockquote.accepts(["*", "*", "whatever", "*", "/"]) str(blockquote) # test stringification blockquote | blockquote blockquote & blockquote blockquote ^ blockquote reversed(blockquote) assert not blockquote.everythingbut().accepts(["/", "*", "whatever", "*", "/"]) assert blockquote.everythingbut().accepts(["*"]) # deliberately seek oblivion assert blockquote.islive(3) assert blockquote.islive(4) assert not blockquote.islive(5) gen = blockquote.strings() assert next(gen) == ["/", "*", "*", "/"]
def to_fsm(treeoid): s_map = {} count = 1 final = {} alphabet = set() def go(treeoid, current=0): nonlocal count s_map[current] = {} for k, v in treeoid.items(): alphabet.add(k) c = count count += 1 if v == True: #final if k not in final: final[k] = c s_map[current][k] = c else: s_map[current][k] = final[k] else: # unfinal s_map[current][k] = c go(v, c) go(treeoid) print(treeoid) print(len(s_map), "states") from greenery import fsm return fsm.fsm(alphabet=alphabet, states=set(s_map.keys()) | set(final.values()), map=s_map, finals=set(final.values()), initial=0)
def test_anything_else_acceptance(): a = fsm( alphabet = {"a", "b", "c", anything_else}, states = {1}, initial = 1, finals = {1}, map = { 1 : {"a" : 1, "b" : 1, "c" : 1, anything_else : 1} }, ) assert a.accepts("d")
def test_invalid_fsms(): # initial state 1 is not a state try: fsm(alphabet={}, states={}, initial=1, finals=set(), map={}) assert False except AssertionError: assert False except Exception: pass # final state 2 not a state try: fsm(alphabet={}, states={1}, initial=1, finals={2}, map={}) assert False except AssertionError: assert False except Exception: pass # invalid transition for state 1, symbol "a" try: fsm(alphabet={"a"}, states={1}, initial=1, finals=set(), map={1: { "a": 2 }}) assert False except AssertionError: assert False except Exception: pass
def test_abstar(): # Buggggs. abstar = fsm.fsm( alphabet = {'a', fsm.anything_else, 'b'}, states = {0, 1}, initial = 0, finals = {0}, map = { 0: {'a': 0, fsm.anything_else: 1, 'b': 0}, 1: {'a': 1, fsm.anything_else: 1, 'b': 1} } ) assert str(from_fsm(abstar)) == "[ab]*"
def test_dead_default(): blockquote = from_fsm(fsm.fsm( alphabet = {"/", "*", fsm.anything_else}, states = {0, 1, 2, 3, 4}, initial = 0, finals = {4}, map = { 0 : {"/" : 1}, 1 : {"*" : 2}, 2 : {"/" : 2, fsm.anything_else : 2, "*" : 3}, 3 : {"/" : 4, fsm.anything_else : 2, "*" : 3}, } ))
def b(): b = fsm( alphabet = {"a", "b"}, states = {0, 1, "ob"}, initial = 0, finals = {1}, map = { 0 : {"a" : "ob", "b" : 1 }, 1 : {"a" : "ob", "b" : "ob"}, "ob" : {"a" : "ob", "b" : "ob"}, }, ) return b
def test_lego_recursion_error(): # Catch a recursion error assert str(from_fsm(fsm.fsm( alphabet = {"0", "1"}, states = {0, 1, 2, 3}, initial = 3, finals = {1}, map = { 0: {"0": 1, "1": 1}, 1: {"0": 2, "1": 2}, 2: {"0": 2, "1": 2}, 3: {"0": 0, "1": 2}, } ))) == "0[01]"
def test_anything_else_acceptance(): a = fsm( alphabet={"a", "b", "c", anything_else}, states={1}, initial=1, finals={1}, map={1: { "a": 1, "b": 1, "c": 1, anything_else: 1 }}, ) assert a.accepts("d")
def test_reverse_brzozowski(): # This is (a|b)*a(a|b) brzozowski = fsm( alphabet = {"a", "b"}, states = {"A", "B", "C", "D", "E"}, initial = "A", finals = {"C", "E"}, map = { "A" : {"a" : "B", "b" : "D"}, "B" : {"a" : "C", "b" : "E"}, "C" : {"a" : "C", "b" : "E"}, "D" : {"a" : "B", "b" : "D"}, "E" : {"a" : "B", "b" : "D"}, }, ) assert brzozowski.accepts("aa") assert brzozowski.accepts("ab") assert brzozowski.accepts("aab") assert brzozowski.accepts("bab") assert brzozowski.accepts("abbbbbbbab") assert not brzozowski.accepts("") assert not brzozowski.accepts("a") assert not brzozowski.accepts("b") assert not brzozowski.accepts("ba") assert not brzozowski.accepts("bb") assert not brzozowski.accepts("bbbbbbbbbbbb") # So this is (a|b)a(a|b)* b2 = reversed(brzozowski) assert b2.accepts("aa") assert b2.accepts("ba") assert b2.accepts("baa") assert b2.accepts("bab") assert b2.accepts("babbbbbbba") assert not b2.accepts("") assert not b2.accepts("a") assert not b2.accepts("b") assert not b2.accepts("ab") assert not b2.accepts("bb") assert not b2.accepts("bbbbbbbbbbbb") # Test string generator functionality. gen = b2.strings() assert next(gen) == ["a", "a"] assert next(gen) == ["b", "a"] assert next(gen) == ["a", "a", "a"] assert next(gen) == ["a", "a", "b"] assert next(gen) == ["b", "a", "a"] assert next(gen) == ["b", "a", "b"] assert next(gen) == ["a", "a", "a", "a"]
def test_adotb(): adotb = fsm.fsm( alphabet = {'a', fsm.anything_else, 'b'}, states = {0, 1, 2, 3, 4}, initial = 0, finals = {4}, map = { 0: {'a': 2, fsm.anything_else: 1, 'b': 1}, 1: {'a': 1, fsm.anything_else: 1, 'b': 1}, 2: {'a': 3, fsm.anything_else: 3, 'b': 3}, 3: {'a': 1, fsm.anything_else: 1, 'b': 4}, 4: {'a': 1, fsm.anything_else: 1, 'b': 1} } ) assert str(from_fsm(adotb)) == "a.b"
def __init__(self, alphabet, states, initial, finals, map): """ create a new MinDFA object. input params - as described in greenery.fsm additional members: is_all_words: flag to indicate (when possible) if the DFA is equal to the entire domain (e.g. create from_fsm dfa_all_words) Relevant for performance improvements (though, if keeping the current __eq__ override, may not be necessary) complement_dfa: MinDFA of the complement dfa of self, e.g: relevant when doing subtraction from 'all'. for performance improvement (avoid computation of complement if could use this member instead). """ self.fsm = fsm(initial, finals, alphabet, states, map) self.is_all_words = MinDFA.Ternary.UNKNOWN self.complement_dfa = None
def test_reduce(): # FSM accepts no strings but has 3 states, needs only 1 asdf = fsm( alphabet = {None}, states = {0, 1, 2}, initial = 0, finals = {1}, map = { 0 : {None : 2}, 1 : {None : 2}, 2 : {None : 2}, }, ) asdf = asdf.reduce() assert len(asdf.states) == 1
def graph2fsm(g): states = set(g.node.keys()) # map alphabet to regex compatible chars sym = 'a' alph_mapper = dict() for state in states: alph_mapper[state] = sym sym = chr(ord(sym) + 1) # transitions: (FROM_STATE -> (INPUT -> TO_STATE)) transistions = dict() for state in states: succs = g.adj.get(state) succs = set(succs.keys()) transistions[state] = dict( map(lambda e: (alph_mapper.get(e), e), succs)) # find start node start_node = "" for (k, v) in g.in_degree().items(): if v == 0: if start_node != "": print("Error: More than one start states!") else: start_node = k # find end nodes end_nodes = dict((k, v) for k, v in g.out_degree().items() if v == 0) end_nodes = set(end_nodes.keys()) # construct fsm from digraph data f = fsm.fsm( alphabet=alph_mapper.values(), states=states, initial=start_node, finals=end_nodes, map=transistions, ) # convert fsm to regex r = lego.from_fsm(f) print("Regex: {}".format(r)) print("Regex Mapping:\n--------------") for (k, v) in alph_mapper.items(): print("{}: \t {}".format(v, k)) return r
def test_reverse_abc(): abc = fsm( alphabet = {"a", "b", "c"}, states = {0, 1, 2, 3, None}, initial = 0, finals = {3}, map = { 0 : {"a" : 1 , "b" : None, "c" : None}, 1 : {"a" : None, "b" : 2 , "c" : None}, 2 : {"a" : None, "b" : None, "c" : 3 }, 3 : {"a" : None, "b" : None, "c" : None}, None : {"a" : None, "b" : None, "c" : None}, }, ) cba = reversed(abc) assert cba.accepts("cba")
def test_difference(a, b): aorb = fsm( alphabet = {"a", "b"}, states = {0, 1, None}, initial = 0, finals = {1}, map = { 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 dfa_to_regex(): received_json = request.get_json(silent=True) constructed_automata = fsm.fsm( alphabet=set(received_json['alphabet']), states=set(received_json['states']), initial=received_json['initial'], finals=set(received_json['finals']), map=received_json['map'], ) constructed_regex = lego.from_fsm(constructed_automata) constructed_regex.reduce() return jsonify({ "regex": str(lego.from_fsm(constructed_automata)) })
def test_dead_default(): ''' You may now omit a transition, or even an entire state, from the map. This affects every usage of `fsm.map`. ''' blockquote = fsm(alphabet={"/", "*", anything_else}, states={0, 1, 2, 3, 4, 5}, initial=0, finals={4}, map={ 0: { "/": 1 }, 1: { "*": 2 }, 2: { "/": 2, anything_else: 2, "*": 3 }, 3: { "/": 4, anything_else: 2, "*": 3 }, }) assert blockquote.accepts(["/", "*", "whatever", "*", "/"]) assert not blockquote.accepts(["*", "*", "whatever", "*", "/"]) str(blockquote) # test stringification blockquote | blockquote blockquote & blockquote blockquote ^ blockquote reversed(blockquote) assert not blockquote.everythingbut().accepts( ["/", "*", "whatever", "*", "/"]) assert blockquote.everythingbut().accepts(["*" ]) # deliberately seek oblivion assert blockquote.islive(3) assert blockquote.islive(4) assert not blockquote.islive(5) gen = blockquote.strings() assert next(gen) == ["/", "*", "*", "/"]
def test_binary_3(): # Binary numbers divisible by 3. # Disallows the empty string # Allows "0" on its own, but not leading zeroes. div3 = fsm( alphabet = {"0", "1"}, states = {"initial", "zero", 0, 1, 2, None}, initial = "initial", finals = {"zero", 0}, map = { "initial" : {"0" : "zero", "1" : 1 }, "zero" : {"0" : None , "1" : None}, 0 : {"0" : 0 , "1" : 1 }, 1 : {"0" : 2 , "1" : 0 }, 2 : {"0" : 1 , "1" : 2 }, None : {"0" : None , "1" : None}, }, ) assert not div3.accepts("") assert div3.accepts("0") assert not div3.accepts("1") assert not div3.accepts("00") assert not div3.accepts("01") assert not div3.accepts("10") assert div3.accepts("11") assert not div3.accepts("000") assert not div3.accepts("001") assert not div3.accepts("010") assert not div3.accepts("011") assert not div3.accepts("100") assert not div3.accepts("101") assert div3.accepts("110") assert not div3.accepts("111") assert not div3.accepts("0000") assert not div3.accepts("0001") assert not div3.accepts("0010") assert not div3.accepts("0011") assert not div3.accepts("0100") assert not div3.accepts("0101") assert not div3.accepts("0110") assert not div3.accepts("0111") assert not div3.accepts("1000") assert div3.accepts("1001")
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, finals = {4}, map = { 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 test_basic(self): dfa1 = get_str_dfa("put|get") dfa2 = get_str_dfa("get|put") self.assertEqual(dfa1, dfa2) dfa3 = get_str_dfa("put") dfa4 = get_str_dfa("get") self.assertEqual(dfa1, dfa3 | dfa4) self.assertEqual(dfa1, dfa4 | dfa3) dfa5 = dfa4 & dfa1 self.assertEqual(dfa5, dfa4) print(dfa4.get_fsm_str()) print(repr(dfa4)) # equiv dfa created directly, with a different set of state numbers equiv_dfa = fsm(alphabet={"e", "g", "t", anything_else}, states={0, 1, 2, 5}, initial=0, finals={5}, map={ 0: { 'g': 1 }, 1: { 'e': 2 }, 2: { 't': 5 }, 5: {} }) dfa6 = MinDFA.dfa_from_fsm(equiv_dfa) res1 = dfa6 == dfa4 print(res1) self.assertFalse(res1) dfa6 = dfa6.get_fsm() dfa4 = dfa4.get_fsm() res2 = dfa6.equivalent(dfa4) print(res2) self.assertTrue(res2) dfa6.reduce() print(repr(dfa6))
def test_reduce(): # FSM accepts no strings but has 3 states, needs only 1 asdf = fsm( alphabet={None}, states={0, 1, 2}, initial=0, finals={1}, map={ 0: { None: 2 }, 1: { None: 2 }, 2: { None: 2 }, }, ) asdf = asdf.reduce() assert len(asdf.states) == 1
def test_bug_28(): # This is (ab*)* and it caused some defects. abstar = fsm( alphabet = {'a', 'b'}, states = {0, 1}, initial = 0, finals = {1}, map = { 0: {'a': 1}, 1: {'b': 1} } ) assert abstar.accepts("a") assert not abstar.accepts("b") assert abstar.accepts("ab") assert abstar.accepts("abb") abstarstar = abstar.star() assert abstarstar.accepts("a") assert not abstarstar.accepts("b") assert abstarstar.accepts("ab") assert not abstar.star().accepts("bb")
def test_bad_alphabet(): # You can use anything you like in your FSM alphabet, but if you try to # convert it to a `lego` object then the only acceptable symbols are single # characters or `fsm.anything_else`. for bad_symbol in [None, (), 0, ("a",), "", "aa", "ab", True]: f = fsm.fsm( alphabet = {bad_symbol}, states = {0}, initial = 0, finals = set(), map = { 0 : {bad_symbol : 0} }, ) try: from_fsm(f) assert False except AssertionError as e: raise Exception("Accepted bad symbol: " + repr(bad_symbol)) except Exception as e: pass
def test_invalid_fsms(): # initial state 1 is not a state try: fsm( alphabet = {}, states = {}, initial = 1, finals = set(), map = {} ) assert False except AssertionError: assert False except Exception: pass # final state 2 not a state try: fsm( alphabet = {}, states = {1}, initial = 1, finals = {2}, map = {} ) assert False except AssertionError: assert False except Exception: pass # invalid transition for state 1, symbol "a" try: fsm( alphabet = {"a"}, states = {1}, initial = 1, finals = set(), map = { 1 : {"a" : 2} } ) assert False except AssertionError: assert False except Exception: pass
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, finals = {3}, map = { 0 : {"a" : 1}, 1 : {"b" : 2}, 2 : {"c" : 3}, } ) assert len((abc + abc).states) == 7 assert len(abc.star().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).states) == 1 assert len((abc - abc).states) == 1
def a(): a = fsm( alphabet={"a", "b"}, states={0, 1, "ob"}, initial=0, finals={1}, map={ 0: { "a": 1, "b": "ob" }, 1: { "a": "ob", "b": "ob" }, "ob": { "a": "ob", "b": "ob" }, }, ) return a
def __init__(self, config, n_global_in, n_global_out): n_layers_start = 5 num_min = 3 self.configuration = config self.global_attributes = GlobalAttributes(self.configuration) self.net_struct = [] state_machine = fsm(alphabet=set(config.fsm['alphabet']), states=set(config.fsm['states']), initial="inicial", finals={"Dense"}, map=config.fsm['map']) candidates = list( itertools.takewhile( lambda c: len(c) <= n_layers_start, itertools.dropwhile(lambda l: len(l) < num_min, state_machine.strings()))) first_layers = list(set([b[0] for b in candidates])) candidates = [ random.choice([z for z in candidates if z[0] == first_layers[l]]) for l in range(len(first_layers)) ] sizes = list(set(map(len, candidates))) random_size = random.choice(sizes) candidates = filter(lambda c: len(c) == random_size, candidates) candidate = random.choice(candidates) candidate = map(lambda lt: Layer([lt], config), candidate) self.net_struct = candidate self.net_struct[0].parameters['input_shape'] = (n_global_in, ) self.net_struct[-1].parameters['output_dim'] = n_global_out self.global_attributes.number_layers = len(self.net_struct)
def test_bug_28(): # This is (ab*)* and it caused some defects. abstar = fsm(alphabet={'a', 'b'}, states={0, 1}, initial=0, finals={1}, map={ 0: { 'a': 1 }, 1: { 'b': 1 } }) assert abstar.accepts("a") assert not abstar.accepts("b") assert abstar.accepts("ab") assert abstar.accepts("abb") abstarstar = abstar.star() assert abstarstar.accepts("a") assert not abstarstar.accepts("b") assert abstarstar.accepts("ab") assert not abstar.star().accepts("bb")
def test_reverse_abc(): abc = fsm( alphabet={"a", "b", "c"}, states={0, 1, 2, 3, None}, initial=0, finals={3}, map={ 0: { "a": 1, "b": None, "c": None }, 1: { "a": None, "b": 2, "c": None }, 2: { "a": None, "b": None, "c": 3 }, 3: { "a": None, "b": None, "c": None }, None: { "a": None, "b": None, "c": None }, }, ) cba = reversed(abc) assert cba.accepts("cba")