diff --git a/analyze.py b/analyze.py index 304bf4b..3fc5163 100644 --- a/analyze.py +++ b/analyze.py @@ -56,6 +56,7 @@ if __name__ == "__main__": #ast = parse_file(args.filename, use_cpp=False) #ast.show() + initial_state = args.initial assign_table = [] state_enums = [] func_table = {} @@ -128,13 +129,16 @@ if __name__ == "__main__": #states = comp_tt.keys() print("States: ", ",".join(states)) print("") - + + reachable_states = [initial_state] props_by_state = {} print("Compact Transition Table:") for n,ms in comp_tt.items(): sstr = ','.join(ms) print(f"{n}->{{{sstr}}}") - + for s in ms: + if not(s in reachable_states): + reachable_states.append(s) # find properties for f in fsm_funcs: sccpv = SwitchCaseCodePropertyVisitor(n, pure_sa) @@ -143,27 +147,37 @@ if __name__ == "__main__": props_by_state[n] = sccpv.properties print("") - properties = {} + print("Reachable States") + + states_by_property = {} for state,props in props_by_state.items(): for prop in props: - if prop in properties: - properties[prop].append(state) + if prop in states_by_property: + states_by_property[prop].append(state) else: - properties[prop] = [state] + states_by_property[prop] = [state] + properties = {} + property_alias = {} + for i,(prop,pstates) in enumerate(states_by_property.items()): + print("foo ", i) + alias = base_10_to_alphabet(i + 1) + property_alias[prop] = alias + properties[alias] = (pstates, prop) + print("Properties") - for prop,pstates in properties.items(): + for prop,(pstates,full_prop) in properties.items(): ss = ','.join(pstates) - print(f" - '{prop}' when {ss}") + print(f" - '{full_prop}' when {ss}") print("") ltls = [] if args.ltlfile is not None: with open(args.ltlfile) as f: ltls = [line.rstrip() for line in f] - - - mod = ModelBuilder(states, args.initial, comp_tt, properties, ltls=ltls) + + + mod = ModelBuilder(reachable_states, initial_state, comp_tt, properties, ltls=ltls) nusmv = mod.generate() if args.output is not None: @@ -175,15 +189,16 @@ if __name__ == "__main__": if args.dot is not None: g = gv.Digraph('G') - + print(props_by_state) + print(property_alias) for state in states: shape = 'circle' - if state == args.initial: + if state == initial_state: shape = 'doublecircle' if state in props_by_state: - pstr = ",".join(props_by_state[state]) - g.node(state, label=state, xlabel=f"{{{pstr}}}", shape=shape) + pstr = ",".join([property_alias[x] for x in props_by_state[state]]) + g.node(state, label=f"{state}\n\n{{{pstr}}}", shape=shape) else: g.node(state, label=state, shape=shape) diff --git a/modelbuilder.py b/modelbuilder.py index c213626..13bec19 100644 --- a/modelbuilder.py +++ b/modelbuilder.py @@ -26,31 +26,6 @@ LTL_FORM = """LTLSPEC {ltl}; """ -A_UPPERCASE = ord('a') -ALPHABET_SIZE = 26 - - -def _decompose(number): - """Generate digits from `number` in base alphabet, least significants - bits first. - - Since A is 1 rather than 0 in base alphabet, we are dealing with - `number - 1` at each iteration to be able to extract the proper digits. - """ - - while number: - number, remainder = divmod(number - 1, ALPHABET_SIZE) - yield remainder - - -def base_10_to_alphabet(number): - """Convert a decimal number to its base alphabet representation""" - - return ''.join( - chr(A_UPPERCASE + part) - for part in _decompose(number) - )[::-1] - class ModelBuilder: def __init__(self, states, initial, transitions, properties, ltls=[], name="main"): self._name = name @@ -59,10 +34,6 @@ class ModelBuilder: self._tran = transitions self._props = properties self._ltls = ltls - - self._propalias = {} - for no,prop in enumerate(properties.keys()): - self._propalias[prop] = base_10_to_alphabet(no + 1) def generate(self): # build model @@ -74,8 +45,7 @@ class ModelBuilder: transitions.append(transition) properties = [] - for prop,states in self._props.items(): - alias = self._propalias[prop] + for alias,(states,prop) in self._props.items(): logic = " | ".join([PROP_LOGIC.format(state=x) for x in states]) prop_str = PROP.format(prop=prop, alias=alias, logic=logic) properties.append(prop_str) diff --git a/utils.py b/utils.py index 08c525a..9f30787 100644 --- a/utils.py +++ b/utils.py @@ -1,5 +1,30 @@ import re +A_UPPERCASE = ord('a') +ALPHABET_SIZE = 26 + + +def _decompose(number): + """Generate digits from `number` in base alphabet, least significants + bits first. + + Since A is 1 rather than 0 in base alphabet, we are dealing with + `number - 1` at each iteration to be able to extract the proper digits. + """ + + while number: + number, remainder = divmod(number - 1, ALPHABET_SIZE) + yield remainder + + +def base_10_to_alphabet(number): + """Convert a decimal number to its base alphabet representation""" + + return ''.join( + chr(A_UPPERCASE + part) + for part in _decompose(number) + )[::-1] + def find_longest_path(paths): ms = 0 mp = None