improved dot generation
This commit is contained in:
parent
2ca5091658
commit
a5a44098b8
45
analyze.py
45
analyze.py
@ -56,6 +56,7 @@ if __name__ == "__main__":
|
|||||||
#ast = parse_file(args.filename, use_cpp=False)
|
#ast = parse_file(args.filename, use_cpp=False)
|
||||||
#ast.show()
|
#ast.show()
|
||||||
|
|
||||||
|
initial_state = args.initial
|
||||||
assign_table = []
|
assign_table = []
|
||||||
state_enums = []
|
state_enums = []
|
||||||
func_table = {}
|
func_table = {}
|
||||||
@ -128,13 +129,16 @@ if __name__ == "__main__":
|
|||||||
#states = comp_tt.keys()
|
#states = comp_tt.keys()
|
||||||
print("States: ", ",".join(states))
|
print("States: ", ",".join(states))
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
reachable_states = [initial_state]
|
||||||
props_by_state = {}
|
props_by_state = {}
|
||||||
print("Compact Transition Table:")
|
print("Compact Transition Table:")
|
||||||
for n,ms in comp_tt.items():
|
for n,ms in comp_tt.items():
|
||||||
sstr = ','.join(ms)
|
sstr = ','.join(ms)
|
||||||
print(f"{n}->{{{sstr}}}")
|
print(f"{n}->{{{sstr}}}")
|
||||||
|
for s in ms:
|
||||||
|
if not(s in reachable_states):
|
||||||
|
reachable_states.append(s)
|
||||||
# find properties
|
# find properties
|
||||||
for f in fsm_funcs:
|
for f in fsm_funcs:
|
||||||
sccpv = SwitchCaseCodePropertyVisitor(n, pure_sa)
|
sccpv = SwitchCaseCodePropertyVisitor(n, pure_sa)
|
||||||
@ -143,27 +147,37 @@ if __name__ == "__main__":
|
|||||||
props_by_state[n] = sccpv.properties
|
props_by_state[n] = sccpv.properties
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
properties = {}
|
print("Reachable States")
|
||||||
|
|
||||||
|
states_by_property = {}
|
||||||
for state,props in props_by_state.items():
|
for state,props in props_by_state.items():
|
||||||
for prop in props:
|
for prop in props:
|
||||||
if prop in properties:
|
if prop in states_by_property:
|
||||||
properties[prop].append(state)
|
states_by_property[prop].append(state)
|
||||||
else:
|
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")
|
print("Properties")
|
||||||
for prop,pstates in properties.items():
|
for prop,(pstates,full_prop) in properties.items():
|
||||||
ss = ','.join(pstates)
|
ss = ','.join(pstates)
|
||||||
print(f" - '{prop}' when {ss}")
|
print(f" - '{full_prop}' when {ss}")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
ltls = []
|
ltls = []
|
||||||
if args.ltlfile is not None:
|
if args.ltlfile is not None:
|
||||||
with open(args.ltlfile) as f:
|
with open(args.ltlfile) as f:
|
||||||
ltls = [line.rstrip() for line in 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()
|
nusmv = mod.generate()
|
||||||
|
|
||||||
if args.output is not None:
|
if args.output is not None:
|
||||||
@ -175,15 +189,16 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
if args.dot is not None:
|
if args.dot is not None:
|
||||||
g = gv.Digraph('G')
|
g = gv.Digraph('G')
|
||||||
|
print(props_by_state)
|
||||||
|
print(property_alias)
|
||||||
for state in states:
|
for state in states:
|
||||||
shape = 'circle'
|
shape = 'circle'
|
||||||
if state == args.initial:
|
if state == initial_state:
|
||||||
shape = 'doublecircle'
|
shape = 'doublecircle'
|
||||||
|
|
||||||
if state in props_by_state:
|
if state in props_by_state:
|
||||||
pstr = ",".join(props_by_state[state])
|
pstr = ",".join([property_alias[x] for x in props_by_state[state]])
|
||||||
g.node(state, label=state, xlabel=f"{{{pstr}}}", shape=shape)
|
g.node(state, label=f"{state}\n\n{{{pstr}}}", shape=shape)
|
||||||
else:
|
else:
|
||||||
g.node(state, label=state, shape=shape)
|
g.node(state, label=state, shape=shape)
|
||||||
|
|
||||||
|
|||||||
@ -26,31 +26,6 @@ LTL_FORM = """LTLSPEC
|
|||||||
{ltl};
|
{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:
|
class ModelBuilder:
|
||||||
def __init__(self, states, initial, transitions, properties, ltls=[], name="main"):
|
def __init__(self, states, initial, transitions, properties, ltls=[], name="main"):
|
||||||
self._name = name
|
self._name = name
|
||||||
@ -59,10 +34,6 @@ class ModelBuilder:
|
|||||||
self._tran = transitions
|
self._tran = transitions
|
||||||
self._props = properties
|
self._props = properties
|
||||||
self._ltls = ltls
|
self._ltls = ltls
|
||||||
|
|
||||||
self._propalias = {}
|
|
||||||
for no,prop in enumerate(properties.keys()):
|
|
||||||
self._propalias[prop] = base_10_to_alphabet(no + 1)
|
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
# build model
|
# build model
|
||||||
@ -74,8 +45,7 @@ class ModelBuilder:
|
|||||||
transitions.append(transition)
|
transitions.append(transition)
|
||||||
|
|
||||||
properties = []
|
properties = []
|
||||||
for prop,states in self._props.items():
|
for alias,(states,prop) in self._props.items():
|
||||||
alias = self._propalias[prop]
|
|
||||||
logic = " | ".join([PROP_LOGIC.format(state=x) for x in states])
|
logic = " | ".join([PROP_LOGIC.format(state=x) for x in states])
|
||||||
prop_str = PROP.format(prop=prop, alias=alias, logic=logic)
|
prop_str = PROP.format(prop=prop, alias=alias, logic=logic)
|
||||||
properties.append(prop_str)
|
properties.append(prop_str)
|
||||||
|
|||||||
25
utils.py
25
utils.py
@ -1,5 +1,30 @@
|
|||||||
import re
|
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):
|
def find_longest_path(paths):
|
||||||
ms = 0
|
ms = 0
|
||||||
mp = None
|
mp = None
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user