def test_complement_node_with_live_ends(self): node = Node('node') node.add_transition(Label({'a': True}), {(node, False)}) complement_node(node, ['a']) assert node.transitions[Label({'a': True})] == [{(node, False)}] assert node.transitions[Label({'a': False})] == [{(LIVE_END, False)}]
def test_is_absorbing(self): node = Node('node') true_label = Label({}) node.add_transition(true_label, [(node, True)]) node.add_transition(Label({'r': True}), [(node, True)]) assert is_absorbing(node)
def test_map_setitem(self): map = LabelsMap() map[Label({'a': True})] = True assert map[Label({'a': True})] == True # map[Label({'a':True})] = False # assert map[Label({'a':True})] == False assert Label({'a': True, 'c': True}) in map assert Label({}) not in map
def test_convert_to_formula(self): boolean_symbols = dict(zip(['a', 'b'], symbols(*['a', 'b']))) assert convert_to_labels( convert_to_formula(Label({'a': True}), boolean_symbols)) == {Label({'a': True})} assert convert_to_labels( convert_to_formula(Label({ 'a': True, 'b': False }), boolean_symbols)) == {Label({ 'a': True, 'b': False })}
def is_dead_end(state): if state is DEAD_END: return True if Label({}) in state.transitions: next_states_set_list = state.transitions[Label({})] assert len(next_states_set_list) == 1 next_states_set = next_states_set_list[0] if index_of(lambda node_flag: node_flag[0] == state and node_flag[1], next_states_set) is not None: return True return False
def _restrict_trans(self, impl, permissible_states): #: :type: FuncDescription trans_func_desc = impl.taus_descs[0] assertions = StrAwareList() for curr_state in permissible_states: free_input_vars = self._get_free_vars(Label(), impl) value_by_arg = self._get_proc_tau_args(curr_state, Label(), 0, impl) next_state = self._underlying_solver.call_func(trans_func_desc, value_by_arg) assertions += self._underlying_solver.assert_( self._underlying_solver.forall_bool(free_input_vars, self._get_permissible_states_clause(next_state, permissible_states))) return assertions
def get_free_sched_vars(self, label) -> list: free_signals = set( filter(lambda sch: sch not in label, self._sched_signals)) _, free_vars = build_signals_values(free_signals, Label()) return free_vars
def _build_label_from_proc_index(self, proc_index: int) -> Label: bits = bin_fixed_list(proc_index, self._nof_proc_bits) label = Label( dict(zip(map(lambda at: at[0], self._proc_arg_type_pairs), bits))) return label
def _to_expr(l:Label, sig_by_name:dict): expr = sympy.true for sig, val in l.items(): sig_by_name[sig.name] = sig s = sympy.Symbol(str(sig)) expr = (expr & s) if val else (expr & ~s) return expr
def test_is_not_absorbing(self): node = Node('node') true_label = Label({}) node.add_transition(true_label, [('dst1', True)]) assert not is_absorbing(node)
def get_intersection(label1, label2): for v in label1: if v in label2 and label1[v] != label2[v]: return None result = dict(label1) result.update(label2) return Label(result)
def _clause_to_formula(clause: Label, bits_by_state: dict) -> str: literals = [] for (var, value) in clause.items(): if isinstance(var, QuantifiedSignal): lit = ['!', ''][value] + var.name else: lit = _state_to_formula(value, bits_by_state) literals.append(lit) return '(' + ' & '.join(literals) + ')'
def _clause_to_formula(clause:Label, bits_by_state:dict) -> str: literals = [] for (var, value) in clause.items(): if isinstance(var, QuantifiedSignal): lit = ['!', ''][value] + var.name else: lit = _state_to_formula(value, bits_by_state) literals.append(lit) return '(' + ' & '.join(literals) + ')'
def is_absorbing(node): true_label = Label({}) sets_of_flagged_nodes = node.transitions.get(true_label) if sets_of_flagged_nodes is None: return False all_next_flagged_nodes = chain(*sets_of_flagged_nodes) return index_of(lambda node_flag: node_flag[0] == node, all_next_flagged_nodes) is not None
def _label_from_clause(clause): """input is AND clause""" label_dict = dict() for l in clause.literals: assert len(l.symbols) == 1, str(l.symbols) symbol = next(iter(l.symbols)) variable = symbol.obj label_dict[variable] = not isinstance(l, NOT) return Label(label_dict)
def _create_automaton(self, node_names, init_node_name, transitions_dict): name_to_node = {} for name in node_names: name_to_node[name] = Node(name) for trans_desc, is_rejecting in transitions_dict.items(): src_node, dst_node = list(map(lambda name: name_to_node[name], trans_desc.split('->'))) src_node.add_transition(Label({}), {(dst_node,is_rejecting)}) return Automaton([{name_to_node[init_node_name]}], set(), set(name_to_node.values()))
def convert_to_labels(formula): if formula == FALSE: return None if formula == TRUE: return {Label({})} labels = set() for c in normalize(OR, formula): labels.add(_label_from_clause(c)) return labels
def __getitem__(self, key:Label): if not isinstance(key, Label): raise TypeError(key) indices = [v for (l, v) in self._value_by_label if set(l.items()).issubset(set(key.items()))] if len(indices) == 0: raise KeyError(key) assert len(indices) == 1, 'return value is not unique: %s: %s' % (str(key), str(indices)) return indices[0]
def filter_label_by_process(self, label, proc_index: int): # TODO: hack filtered_label = dict() for signal, value in label.items(): if signal in self._sched_signals: filtered_label[signal] = value elif signal in self._is_active_signals: # TODO: why do we need is_active of OTHER processes?! filtered_label[signal] = value elif signal.binding_indices[0] == proc_index: filtered_label[signal] = value return Label(filtered_label)
def _label_states_with_outvalues(lts:LTS, filter='all'): dot_lines = StrAwareList() for state in lts.states: signal_vals_pairs = [(var, vals) for (var, vals) in lts.model_by_name.items() if var in filter or filter == 'all'] outvals = dict([(var, vals[Label({'state': state})]) # TODO: hack for (var, vals) in signal_vals_pairs]) outvals_str = _convert_to_dot(outvals) if outvals_str != '': dot_lines += '"{state}"[label="{out}\\n({state})"]'.format(state=state, out=outvals_str) return dot_lines
def test_map_getitem(self): label_map = LabelsMap() label_map[Label({'a': False, 'b': False})] = True assert Label({'a': False, 'b': False}) in label_map assert label_map[Label({'a': False, 'b': False})] == True assert Label({'a': False, 'b': False, 'c': False}) in label_map assert label_map[Label({'a': False, 'b': False, 'c': False})] == True assert Label({'a': True, 'b': False}) not in label_map assert Label({'a': True}) not in label_map
def __getitem__(self, key:Label): if not isinstance(key, Label): raise TypeError(key) indices = [v for (l, v) in self._value_by_label if set(l.items()).issubset(set(key.items()))] assert len(indices) == 0 or len(indices) == 1, str(indices) + ', for ' + str(key) if len(indices) == 1: return indices[0] elif len(indices) == 0: raise KeyError(key) else: assert 0, str(key) + ' leads to ambiguity: ' + str(indices)
def _build_func_model_from_smt(self, func_smt_lines, func_desc:FuncDescription) -> dict: """ Return transition(output) graph {label:output} """ func_model = {} for l in func_smt_lines: # (get-value ((tau t0 true true))) l = l.replace('get-value', '').replace('(', '').replace(')', '') tokens = l.split() if tokens[0] != func_desc.name: continue values = self._parse_values(tokens[1:]) # the very first - func_name args = Label(func_desc.get_args_dict(values[:-1])) func_model[args] = values[-1] return func_model
def __getitem__(self, key: Label): if not isinstance(key, Label): raise TypeError(key) indices = [ v for (l, v) in self._value_by_label if set(l.items()).issubset(set(key.items())) ] assert len(indices) == 0 or len( indices) == 1, str(indices) + ', for ' + str(key) if len(indices) == 1: return indices[0] elif len(indices) == 0: raise KeyError(key) else: assert 0, str(key) + ' leads to ambiguity: ' + str(indices)
def _get_next_state_restricted_condition(self, state, only_states, tau_desc:FuncDescription, state_arg_name:str): input_signals = [var for var,ty in tau_desc.inputs if var != state_arg_name] values_by_signal, free_vars = build_signals_values(input_signals, Label()) args = {state_arg_name: state} args.update(values_by_signal) next_state_expr = self._underlying_solver.call_func(tau_desc, args) or_clauses = [] for possible_state in only_states: or_clauses.append(self._underlying_solver.op_eq(next_state_expr, possible_state)) condition = self._underlying_solver.forall_bool(free_vars, self._underlying_solver.op_or(or_clauses)) return condition
def _smt_out(self, label:Label, smt_m:str, q:Node) -> str: conjuncts = [] args_dict = self._build_args_dict(smt_m, label, q) for sig, val in label.items(): if sig not in self.descr_by_output: continue out_desc = self.descr_by_output[sig] condition_on_out = self.solver.call_func(out_desc, args_dict) if val is False: condition_on_out = self.solver.op_not(condition_on_out) conjuncts.append(condition_on_out) condition = self.solver.op_and(conjuncts) return condition
def _get_tok_rings_safety_props( self) -> StrAwareList: # TODO: should be able to specify states! """ Return (in SMT form, constraints on non-wrapped tau function): G(tok & !sends -> Xtok(tau(!prev))) G(sends -> tok) G(sends -> X!tok(!prev)) G(Xtok(prev)) G(!tok -> !Xtok(!prev)) """ smt_lines = StrAwareList() tau_desc = self.taus_descs[0] tau_signals = self.orig_inputs[0] tok_func_desc = self.outvar_desc_by_process[0][self._has_tok_signal] sends_func_desc = self.outvar_desc_by_process[0][self._sends_signal] prev_is_false_label = Label({self._sends_prev_signal: False}) prev_is_true_label = Label({self._sends_prev_signal: True}) states = self.states_by_process[0] for state in states: state_arg = {self.state_arg_name: state} has_tok_expr = call_func(tok_func_desc, state_arg) sends_tok_expr = call_func(sends_func_desc, state_arg) _, free_vars = build_signals_values(tau_signals, prev_is_false_label) nprev_arg, _ = build_signals_values(tau_signals, prev_is_false_label) nprev_state_arg = add_dicts(nprev_arg, state_arg) prev_arg, _ = build_signals_values(tau_signals, prev_is_true_label) prev_state_arg = add_dicts(prev_arg, state_arg) tau_nprev_expr = call_func(tau_desc, nprev_state_arg) tok_of_tau_nprev_expr = call_func( tok_func_desc, {self.state_arg_name: tau_nprev_expr}) tau_prev_expr = call_func(tau_desc, prev_state_arg) tok_of_tau_prev_expr = call_func( tok_func_desc, {self.state_arg_name: tau_prev_expr}) # tok_dont_disappear = forall_bool( free_vars, op_implies(op_and([has_tok_expr, op_not(sends_tok_expr)]), tok_of_tau_nprev_expr)) sends_with_token_only = forall_bool( free_vars, op_implies(sends_tok_expr, has_tok_expr)) sends_means_release = forall_bool( free_vars, op_implies(sends_tok_expr, op_not(tok_of_tau_nprev_expr))) sends_prev_means_acquire = forall_bool(free_vars, tok_of_tau_prev_expr) no_sends_prev_no_tok_means_no_next_tok = forall_bool( free_vars, op_implies(op_not(has_tok_expr), op_not(tok_of_tau_nprev_expr))) smt_lines += [ tok_dont_disappear, sends_with_token_only, sends_means_release, sends_prev_means_acquire, no_sends_prev_no_tok_means_no_next_tok ] return smt_lines
def test_complement_node_with_live_ends2(self): node = Node('node') complement_node(node, ['a']) assert node.transitions[Label({})] == [{(LIVE_END, False)}]
def test_complement_node_with_live_ends3(self): node = Node('node') node.add_transition(Label({}), {(node, False)}) complement_node(node, ['a']) assert node.transitions[Label({})] == [{(node, False)}]
def test_dead_end(self): node = Node('node') node.add_transition(Label({}), {(node, True)}) assert is_dead_end(node)
def test_get_intersection(self): assert get_intersection(Label({}), Label({})) == Label({}) assert get_intersection(Label({'a': True}), Label({})) == Label({'a': True}) assert get_intersection(Label({'a': True}), Label({'b': False})) == Label({ 'a': True, 'b': False }) assert get_intersection(Label({'a': True}), Label({'a': False })) is None assert get_intersection(Label({'a': False}), Label({ 'a': False, 'b': True })) == Label({ 'a': False, 'b': True })