def generateDependencyDict(ruleListND,adtreeFieldOrder): ''' Generate a dictionary of dependency for entries in the n-dim rule list. This operation should (asserted) be performed after the function _removeRedundancy (removal of redundant rules). Definition of dependency: if there is a directed dependency edge A -> B, it means that 1) A has higher priority than B, AND 2) A overwrites (some) of B's decisions (in other words, rule A and B must yield different decisions and there are overlaps of predicates between them). Exception: e.g., A -> M -> N -> C and A is fully covered by M, then there is no need to have A -> C (in other words, A and C becomes independent conditioned on M). NOTE: the exception is not be good enough to fully remove conditional independence. But this will not falsely remove legitimate dependency in the graph. So it will not affect the correctness of the rule list decomposition following the dependency generation, but merely speed up the generateDependencyDict function. How: two nested loops over the rule list. Returns: 1) the dependency dictionary 2) the dot code to plot the dependency graph ''' #dictDep={} '-----------code------------' code='' code+='''digraph { rankdir="TB" edge [fontsize=10] node [fontsize=10,margin=0.0] ''' for iRule,_ in enumerate(ruleListND): code+='%d' % iRule+' [label="'+'%d' % iRule+'",shape=oval];\n' '-----------code------------' for iRule,rule in zip(range(len(ruleListND)),ruleListND)[0:-1][::-1]: #from second last to first for iRefRule,refRule in zip(range(len(ruleListND)),ruleListND)[iRule+1:]: #from current rule's next rule onwards #print iRule #print iRefRule ruleOverlapped=rulesOverlapped(rule,refRule,adtreeFieldOrder,'prefix') ruleCovered=ruleIsCovered(rule,refRule,adtreeFieldOrder,'prefix') sameDecision=(refRule['decision']==rule['decision']) if not sameDecision and ruleOverlapped: #============ '-----------code------------' code+='%d' % iRule+' -> '+'%d' % iRefRule+';\n' '-----------code------------' #============ if ruleCovered:#ruleCovered is a special case of ruleOverlapped break #else: continue searching code+='}\n' #return (dictDep,code) return code
def _removeRedundancy(ruleListND,adtreeFieldOrder,fmt='prefix'): ''' Remove redundancy (RR) in n-dim rule list. fmt:'prefix' - prefix rule or 'range' - range rule How: go through the rules from lowest priority to highest. For each rule, compare against reference rules with priority lower than it (with order from highest to lowest priority). When can be sure if a rule can be removed: if it is completely covered by a reference rule and they have the same decision. When can be sure if a rule definitely cannot be removed: if it overwrites a reference rule (i.e., they make different decisions and they have some overlap in covered space). If a rule can surely be removed, remove it from the list, and start the whole process all over again with the new list; if a rule cannot be removed surely, skip the rest of the process of comparing it against its reference rules, and go on to the next rule. ''' continueRR=True while continueRR: continueRR=False outerLoopBreak=False for iRule,rule in zip(range(len(ruleListND)),ruleListND)[0:-1][::-1]: #from second last to first for refRule in ruleListND[iRule+1:]: #from current rule's next rule onwards #print rule #print refRule ruleOverlapped=rulesOverlapped(rule,refRule,adtreeFieldOrder,fmt) ruleCovered=ruleIsCovered(rule,refRule,adtreeFieldOrder,fmt) sameDecision=(refRule['decision']==rule['decision']) if sameDecision and ruleCovered: #remove rule, restart the looping all over again ruleListND.remove(rule) #print len(ruleListND) outerLoopBreak=True continueRR=True break if not sameDecision and ruleOverlapped: #rule should not be removed, skip lower ref rules break #else: continue searching if outerLoopBreak: break #from acl.parse import printRuleListND #printRuleListND(ruleListND,adtreeFieldOrder) return ruleListND