def test_get_next_states(self): state = Node('init') sig_r, sig_g = Signal('r'), Signal('g') node_r = Node('r') node_rg = Node('rg') node_nr_g = Node('!rg') _ = False edge_to_r = {(node_r, _)} edge_to_rg = {(node_rg, _)} edge_to_not_r_g = {(node_nr_g, _)} state.add_transition({sig_r:True}, edge_to_r) state.add_transition({sig_r:True, sig_g:True}, edge_to_rg) state.add_transition({sig_r:False, sig_g:True}, edge_to_not_r_g) next_states = get_next_states(state, Label({sig_r:False, sig_g:False})) assert len(next_states) == 0 next_states = get_next_states(state, Label({sig_r:False, sig_g:True})) assert len(next_states) == 1 self._are_equal_sequences({node_nr_g}, next_states) next_states = get_next_states(state, Label({sig_r:True, sig_g:True})) assert len(next_states) == 2 self._are_equal_sequences({node_r, node_rg}, next_states)
def test_simplify_edge_labels___basic2(self): r = Signal('r') g = Signal('g') edge_labels = dict() edge_labels[('t0', 't1')] = [{r: True, g: False}] edge_labels[('t0', 't2')] = [{r: False, g: False}] simplified_edge_labels = simplify_edge_labels(edge_labels) self.assertDictEqual(simplified_edge_labels, edge_labels)
def test_simplify_edge_labels___complex(self): r = Signal('r') g = Signal('g') x = Signal('x') edge_labels = dict() edge_labels[('t0', 't1')] = [{r: True, g: False}, {r: True, g: True}] edge_labels[('t0', 't2')] = [{r: True, g: False}] edge_labels[('t2', 't0')] = [{r: True, g: True}] edge_labels[('t0', 't0')] = [{ r: True, g: True }, { r: True, g: False, x: False }] simplified_edge_labels = simplify_edge_labels(edge_labels) self.assertDictEqual( simplified_edge_labels, { ('t0', 't1'): [{ r: True }], ('t0', 't1'): [{ r: True }], ('t0', 't2'): [{ r: True, g: False }], ('t2', 't0'): [{ r: True, g: True }], ('t0', 't0'): [{ r: True, g: True }, { r: True, x: False }], })
def visit_signal(self, signal:Signal): dst_form_prop = self.dstFormPropManager.get_dst_form_prop(signal.name) # To dualize a proposition, dualize: # 1. ext_label # 2. dst_name # We need (2) since the dual automaton has dualized state names. dual_dst_form_prop = DstFormulaProp(dst_form_prop.ext_label.dual(), _dualize_node(dst_form_prop.dst_state)) dual_signal = Signal(self.dstFormPropManager.get_add_signal_name(dual_dst_form_prop)) return dual_signal
def tests_all(self): input_signals, output_signals, data_by_name = parse( test_string_ltl, test_string_part) exp_input_signals = [ Signal(n) for n in 'idle request0 request1'.split() ] assert set(input_signals) == set(exp_input_signals) exp_output_signals = [Signal(n) for n in 'grant0 grant1'.split()] assert set(output_signals) == set(exp_output_signals) for (k, v) in data_by_name.items(): print(k, v) u1_assumptions, u1_guarantees = data_by_name['u1'] assert len(u1_assumptions) == 1 assert len(u1_guarantees) == 3 u2_assumptions, u2_guarantees = data_by_name['u2'] assert len(u2_assumptions) == 2 assert len(u2_guarantees) == 3
def _parse_signals_from_lines(signal_lines: list) -> list: signals_raw = chain(*[l.split()[1:] for l in signal_lines]) signals = [Signal(n.strip()) for n in signals_raw] return signals
def convert(spec: Spec, nof_IDs: int or None, ltl_to_atm: LTLToAutomaton) -> Spec: # (E.g. EG¬g ∧ AGEF¬g ∧ EFg) # The algorithm is: # collect all E-subformulas # for each unique E-subformula: # introduce new v-variable if not yet introduced # if nof_IDs is not given: # nof_IDs = the number of states in all existential automata # # nof_IDs defines the range of every v-variable # introduce nof_IDs d-variables (each is a valuation of all inputs) # for each unique A-subformula: # introduce p-variable # for each unique A-subformula: # create an LTL formula (0) # for each unique E-subformula: # create an LTL formula (1) # create the top-level formula (2) # create the conjunction (0) & (1) & (2) # //(nope, we don't do this) inline back A-subformulas (replace their p by the path formulas (without 'A')) # replace existential propositions by 'v != 0' # return the result spec = Spec(spec.inputs, spec.outputs, NNFNormalizer().dispatch(spec.formula)) atomizer = CTLAtomizerVisitor('__p') top_formula = atomizer.dispatch(spec.formula) exist_props = [p for (p, f) in atomizer.f_by_p.items() if f.name == 'E'] if nof_IDs is None: atm_by_exist_p = dict( (p, ltl_to_atm.convert(atomizer.f_by_p[p].arg, '__q_' + p.arg1.name)) for p in exist_props) nof_IDs = sum(len(atm.nodes) for atm in atm_by_exist_p.values()) logging.info("k = %i", nof_IDs) v_bits_by_exist_p = dict(( p, tuple( reversed([ Signal('__v%s_%i' % (p.arg1.name.replace('_', ''), i)) for i in range(ceil(log(nof_IDs + 1, 2)) or 1) ])) # NB: +1 to account for 0 ) for p in exist_props) # type: Dict[BinOp, SignalsTuple] ordered_inputs = tuple(spec.inputs) # type: SignalsTuple dTuple_by_id = dict( (j, tuple(Signal('__d%i_%s' % (j, i)) for i in ordered_inputs)) for j in range(1, nof_IDs + 1)) # type: Dict[int, SignalsTuple] univ_props_to_inline = set(atomizer.f_by_p.keys()) - \ _calc_nested_props(atomizer.f_by_p) - \ set(exist_props) ltl_formula = top_formula # such props can only be mentioned in the top_formula ltl_formula = _inline_univ_p( ltl_formula, dict( (p, atomizer.f_by_p[p]) for p in univ_props_to_inline)) ltl_formula &= _conjunction( _create_LTL_for_A_formula(p, atomizer.f_by_p[p].arg) for p in set(atomizer.f_by_p) - set(exist_props) - univ_props_to_inline) ltl_formula &= _conjunction( _create_LTL_for_E_formula(v_bits_by_exist_p[p], atomizer.f_by_p[p].arg, dTuple_by_id, ordered_inputs) for p in exist_props) ltl_formula = _replace_exist_propositions(ltl_formula, v_bits_by_exist_p, nof_IDs) logging.debug("exist propositions: \n%s", pformat([ep.arg1 for ep in v_bits_by_exist_p])) new_outputs = list(chain(*v_bits_by_exist_p.values())) + \ list(chain(*dTuple_by_id.values())) + \ list(p.arg1 for p in set(atomizer.f_by_p) - set(exist_props) - univ_props_to_inline) spec = Spec(spec.inputs, set(new_outputs) | spec.outputs, ltl_formula) return spec
def sig_prop(name:str) -> Tuple[Signal, BinOp]: return Signal(name),\ BinOp('=', Signal(name), Number(1))
def test_simplify_edge_labels___bug(self): # ('t2', 't5') : #[{prev_0: True, mlocked_0: True, sready_0: True, mbusreq_0: True}, # {prev_0: True, mlocked_0: True, sready_0: False, mbusreq_0: True}, # {prev_0: True, mlocked_0: False, sready_0: True, mbusreq_0: False}, # {prev_0: True, mlocked_0: True, sready_0: True, mbusreq_0: False}, # {prev_0: True, mlocked_0: True, sready_0: False, mbusreq_0: False}, # {prev_0: True, mlocked_0: False, sready_0: False, mbusreq_0: False}, # {prev_0: True, mlocked_0: False, sready_0: False, mbusreq_0: True}, # {prev_0: True, mlocked_0: False, sready_0: True, mbusreq_0: True}] # was simplified into: #[{prev_0: True, sready_0: True}, # {prev_0: True, mbusreq_0: True}, # {prev_0: True, mlocked_0: False}] # but the right solution is: # [{prev_0: True}] # ------------------------------------------------ edge_labels = dict() edge_labels[('t2', 't5')] = [{ Signal('prev'): True, Signal('mlocked'): True, Signal('sready'): True, Signal('mbusreq'): True }, { Signal('prev'): True, Signal('mlocked'): True, Signal('sready'): False, Signal('mbusreq'): True }, { Signal('prev'): True, Signal('mlocked'): False, Signal('sready'): True, Signal('mbusreq'): False }, { Signal('prev'): True, Signal('mlocked'): True, Signal('sready'): True, Signal('mbusreq'): False }, { Signal('prev'): True, Signal('mlocked'): True, Signal('sready'): False, Signal('mbusreq'): False }, { Signal('prev'): True, Signal('mlocked'): False, Signal('sready'): False, Signal('mbusreq'): False }, { Signal('prev'): True, Signal('mlocked'): False, Signal('sready'): False, Signal('mbusreq'): True }, { Signal('prev'): True, Signal('mlocked'): False, Signal('sready'): True, Signal('mbusreq'): True }] simplified_edge_labels = simplify_edge_labels(edge_labels) # kinda hack - returns strings instead of Signals.. self.assertDictEqual(simplified_edge_labels, {('t2', 't5'): [{ Signal('prev'): True }]})