def _fixEventEdge(edge, system, only_print=False): """ fix a bad edge caused by external event :param edge: the bad edge :param system: the IoTSystem :return: [[patches], [patches], ...], each 'patches' represents a possible fix """ ts = system.transition_system # First: find all possible actions action_list = list() for action, dst_field in system.getAction(edge.dst_field, False): # after the external event, what action can be triggered? dst_label = system.getLabel(dst_field) ap_dict = dict() for ap, value in zip(ts.ap_list, dst_label): ap_dict[ap] = value if not calculateBoolean(edge.ltl_req, ap_dict): # is good for redirecting, doesn't violate ltl by entering accepting cluster action_list.append(action) # Second: get the correct trigger action trigger = edge.action # Third: find minimum condition that only cover the source state of the edge using hitting set src_label = ts.label_list[edge.src_index_ts] src_ap_list = [(ap if src_label[index] else '!' + ap) for index, ap in enumerate(ts.ap_list) if '.' in ap] hitting_set_list = list() for trans in ts.trans_list: if trans.act == edge.action and ts.state_list[ trans.src_index].field != edge.src_field: label = system.getLabel(ts.state_list[trans.src_index].field) conflict_ap_list = [ '!' + ap if label[index] else ap for index, ap in enumerate(ts.ap_list) if '.' in ap ] hitting_set_list.append(conflict_ap_list) condition = hittingSet(src_ap_list, hitting_set_list) if only_print: print('trigger: %s, condition: %s' % (trigger, str(condition))) else: # return all possible patches result = list() for action in action_list: new_tap = Tap(action, trigger, condition) result.append([Patch('add', '', new_tap)]) return result
def _fixConditionGenerator(system, ltl, record_exp_list, include_orig=False): """ generate a set of bad edge conditions (trigger, condition, possible_actions_list) another return value is a set of all other edge conditions in safety or boundary [(trigger, condition)] .. :param system: :param ltl: :return: """ bad_edges, other_edges = _getBadEdges(system, ltl, record_exp_list) buchi_ltl = Buchi.ltlToBuchi(ltl) result = list() others = list() for bad_edge in bad_edges: ap_list = [ap for ap in system.getApList(bad_edge.src_field) if '@' not in ap and 'trigger' not in ap] ap_list = ap_list + ['!' + ap for ap in system.getAllAp() if '@' not in ap and 'trigger' not in ap and ap not in ap_list and ap not in system.tap_dict] condition = ' & '.join(ap_list) trigger = bad_edge.action action_list = list() for action, dst_field in system.getAction(src_field=bad_edge.dst_field, ext=False): label = system.getLabel(dst_field) ap_dict = dict() for value, ap in zip(label, system.transition_system.ap_list): ap_dict[ap] = value ap_dict = {**ap_dict, **{key: _recordSatisfy(action, key) for key in record_exp_list}} if not calculateBoolean(_getLTLReq(buchi_ltl, bad_edge.src_index_ltl, bad_edge.dst_index_ltl), ap_dict): action_list.append(action) result.append((trigger, condition, action_list)) if include_orig: for k, tap in system.tap_dict.items(): condition = ' & '.join(tap.condition) trigger = tap.trigger action_list = [tap.action] result.append((trigger, condition, action_list)) for edge in other_edges: # should add every edge that doesn't trigger any rule if not system.isTriggeredState(edge.dst_field): ap_list = [ap for ap in system.getApList(edge.src_field) if '@' not in ap and 'trigger' not in ap] ap_list = ap_list + ['!' + ap for ap in system.getAllAp() if '@' not in ap and 'trigger' not in ap and ap not in ap_list and ap not in system.tap_dict] condition = ' & '.join(ap_list) trigger = edge.action others.append((trigger, condition)) else: for edge in other_edges: ap_list = [ap for ap in system.getApList(edge.src_field) if '@' not in ap and 'trigger' not in ap] ap_list = ap_list + ['!' + ap for ap in system.getAllAp() if '@' not in ap and 'trigger' not in ap and ap not in ap_list and ap not in system.tap_dict] condition = ' & '.join(ap_list) trigger = edge.action others.append((trigger, condition)) return result, others
def drawPatchList(system, ltl, patch_list, file_name): """ given system and ltl property, draw graph representation of certain patches as png :param system: the smart home system :param ltl: ltl formula :param patch_list: the patch_list (FixPatch) :param file_name: file to be written :return: """ ts = system.transition_system buchi_ts = Buchi.tsToGenBuchi(ts) buchi_ltl = Buchi.ltlToBuchi(ltl) (buchi_final, pairs) = Buchi.product(buchi_ts, buchi_ltl) group = [s2 for s1, s2 in pairs] modified_buchi = ModifiedBuchi(buchi_final) field_list = [state.field for state in ts.state_list] for edge_index, edge in enumerate(buchi_final.edge_list): src_index_ts = pairs[edge.src][0] dst_index_ts = pairs[edge.dst][0] src_index_ltl = pairs[edge.src][1] dst_index_ltl = pairs[edge.dst][1] src_field = field_list[src_index_ts] dst_field = field_list[dst_index_ts] action = _getAction(ts, src_field, dst_field) if '>' in action: # this is an action triggered by some old rule # should see if it's not triggered in new rule rule_dict = dict([(tap_name, translateTapToRule(tap)) for tap_name, tap in system.tap_dict.items()]) old_rule_name = re.match(r'rule\((?P<rule_name>\w+)\)->[^ ]+', action).group('rule_name') old_rule = rule_dict[old_rule_name] for patch in patch_list: if patch.type == 'delete' and patch.rule_name == old_rule_name: # then this edge is deleted modified_buchi.markDeletedEdge(edge_index) break if patch.type == 'change' and patch.rule_name == old_rule_name: # then this rule is changed, need to see whether edge still triggered new_rule = patch.rule if isinstance(new_rule, ESERule): orig_field = system.getLastStateField( new_rule.trigger, src_field) if orig_field: if not system.apSatisfied(new_rule.condition, orig_field): # then this rule is not triggered anymore modified_buchi.markDeletedEdge(edge_index) break elif '.' in action: # this is an external event # should see if some new rules trigger this for patch in patch_list: new_rule = patch.rule add_edge_flag = 0 if patch.type in ('add', 'change') and not system.isTriggeredState(dst_field) and\ new_rule.trigger == action: if isinstance(new_rule, EERule): # should add an new edge add_edge_flag = 1 elif isinstance(new_rule, ESERule) and \ system.apSatisfied(new_rule.condition, src_field): # should add an new edge add_edge_flag = 1 if add_edge_flag: # this is an new edge, redirection new_field = system.applyActionWithoutTriggering( new_rule.action, dst_field) new_index_ts = ts.getIndex( new_field) # which node it goes in ts ap_list = ts.ap_list new_label = system.getLabel(new_field) var_dict = dict() for ap, label in zip(ap_list, new_label): var_dict[ap] = label # use var_dict to calculate which edge it goes in ltl buchi automata new_index_ltl = -1 # which node it goes in ltl for e in buchi_ltl.edge_list: if e.src == src_index_ltl: if calculateBoolean(e.ap, var_dict): new_index_ltl = e.dst src_final_index = pairs.index( (src_index_ts, src_index_ltl)) new_final_index = pairs.index( (new_index_ts, new_index_ltl)) modified_buchi.markDeletedEdge(edge_index) modified_buchi.addNewEdge(src_final_index, new_final_index) break modified_buchi.writeToGv(file_name, group)
def drawPatch(system, ltl, patch, file_name): """ given system and ltl property, draw graph representation of certain patch as png :param system: the smart home system :param ltl: ltl formula :param patch: the patch (FixPatch) :param file_name: file to be written :return: """ ts = system.transition_system buchi_ts = Buchi.tsToGenBuchi(ts) buchi_ltl = Buchi.ltlToBuchi(ltl) (buchi_final, pairs) = Buchi.product(buchi_ts, buchi_ltl) group = [s2 for s1, s2 in pairs] modified_buchi = ModifiedBuchi(buchi_final) rule_dict = dict([(tap_name, translateTapToRule(tap)) for tap_name, tap in system.tap_dict.items()]) new_rule = None if patch.type == 'delete' else patch.rule old_rule = None if patch.type == 'add' else rule_dict[patch.rule_name] field_list = [state.field for state in ts.state_list] for edge_index, edge in enumerate(buchi_final.edge_list): src_index_ts = pairs[edge.src][0] dst_index_ts = pairs[edge.dst][0] src_index_ltl = pairs[edge.src][1] dst_index_ltl = pairs[edge.dst][1] src_field = field_list[src_index_ts] dst_field = field_list[dst_index_ts] action = _getAction(ts, src_field, dst_field) if '>' in action: # this is an action triggered by a rule # is it handled by old rule? flag_old, flag_new = False, False if old_rule: old_rule_name = patch.rule_name if old_rule_name in action: # handled flag_old = True # is it handled by new rule? if new_rule: if isinstance(new_rule, ESERule): # TODO: should check if this is the correct! should it be last state? if system.apSatisfied(new_rule.condition, src_field): # handled flag_new = True elif isinstance(new_rule, EERule): # handled flag_new = True if flag_old and not flag_new: # this edge is deleted modified_buchi.markDeletedEdge(edge_index) else: # this is an external event if '.' in action: # it is not handled by old rule # is it handled by new rule? old rule? if new_rule: flag_new, flag_old = False, False if new_rule.trigger == action: if isinstance(new_rule, EERule): flag_new = True elif isinstance(new_rule, ESERule): if system.apSatisfied(new_rule.condition, src_field): flag_new = True if old_rule: if old_rule.trigger == action: if isinstance(old_rule, EERule): flag_old = True elif isinstance(old_rule, ESERule): if system.apSatisfied(old_rule.condition, src_field): flag_old = True if flag_new and not flag_old: # this is a new triggered edge, redirection new_field = system.applyActionWithoutTriggering( new_rule.action, dst_field) new_index_ts = ts.getIndex( new_field) # which node it goes in ts ap_list = ts.ap_list new_label = system.getLabel(new_field) var_dict = dict() for ap, label in zip(ap_list, new_label): var_dict[ap] = label # use var_dict to calculate which edge it goes in ltl buchi automata new_index_ltl = -1 # which node it goes in ltl for e in buchi_ltl.edge_list: if e.src == src_index_ltl: if calculateBoolean(e.ap, var_dict): new_index_ltl = e.dst src_final_index = pairs.index( (src_index_ts, src_index_ltl)) new_final_index = pairs.index( (new_index_ts, new_index_ltl)) modified_buchi.markDeletedEdge(edge_index) modified_buchi.addNewEdge(src_final_index, new_final_index) modified_buchi.writeToGv(file_name, group)