def AdornRule(derivedPreds, clause, newHead, ignoreUnboundDPreds=False, hybridPreds2Replace=None): """ Adorns a horn clause using the given new head and list of derived predicates """ assert len(list(iterCondition(clause.head))) == 1 hybridPreds2Replace = hybridPreds2Replace or [] adornedHead = AdornedUniTerm(clause.head, newHead.adornment) sip = BuildNaturalSIP(clause, derivedPreds, adornedHead, hybridPreds2Replace=hybridPreds2Replace, ignoreUnboundDPreds=ignoreUnboundDPreds) bodyPredReplace = {} def adornment(arg, headArc, x): if headArc: # Sip arc from head # don't mark bound if query has no bound/distinguished terms return (arg in x and arg in adornedHead.getDistinguishedVariables(True)) \ and 'b' or 'f' else: return arg in x and 'b' or 'f' for literal in iterCondition(sip.sipOrder): op = GetOp(literal) args = GetArgs(literal) if op in derivedPreds or (op in hybridPreds2Replace if hybridPreds2Replace else False): for N, x in IncomingSIPArcs(sip, getOccurrenceId(literal)): headArc = len(N) == 1 and N[0] == GetOp(newHead) if not set(x).difference(args): # A binding # for q is useful, however, only if it is a binding for an argument of q. bodyPredReplace[literal] = AdornedUniTerm(NormalizeUniterm(literal), [adornment(arg, headArc, x) for arg in args], literal.naf) # For a predicate occurrence with no incoming # arc, the adornment contains only f. For our purposes here, # we do not distinguish between a predicate with such an # adornment and an unadorned predicate (we do in order to support open queries) if literal not in bodyPredReplace and ignoreUnboundDPreds: bodyPredReplace[literal] = AdornedUniTerm(NormalizeUniterm(literal), ['f' for arg in GetArgs(literal)], literal.naf) if hybridPreds2Replace: atomPred = GetOp(adornedHead) if atomPred in hybridPreds2Replace: adornedHead.setOperator(URIRef(atomPred + u'_derived')) for bodAtom in [bodyPredReplace.get(p, p) for p in iterCondition(sip.sipOrder)]: bodyPred = GetOp(bodAtom) if bodyPred in hybridPreds2Replace: bodAtom.setOperator(URIRef(bodyPred + u'_derived')) rule = AdornedRule(Clause(And([bodyPredReplace.get(p, p) for p in iterCondition(sip.sipOrder)]), adornedHead)) rule.sip = sip return rule
def AdornRule(derivedPreds, clause, newHead, ignoreUnboundDPreds=False, hybridPreds2Replace=None): """ Adorns a horn clause using the given new head and list of derived predicates """ assert len(list(iterCondition(clause.head))) == 1 hybridPreds2Replace = hybridPreds2Replace or [] adornedHead = AdornedUniTerm(clause.head, newHead.adornment) sip = BuildNaturalSIP(clause, derivedPreds, adornedHead, hybridPreds2Replace=hybridPreds2Replace, ignoreUnboundDPreds=ignoreUnboundDPreds) bodyPredReplace = {} def adornment(arg, headArc, x): if headArc: # Sip arc from head # don't mark bound if query has no bound/distinguished terms return (arg in x and arg in adornedHead.getDistinguishedVariables(True)) \ and 'b' or 'f' else: return arg in x and 'b' or 'f' for literal in iterCondition(sip.sipOrder): op = GetOp(literal) args = GetArgs(literal) if op in derivedPreds or (op in hybridPreds2Replace if hybridPreds2Replace else False): for N, x in IncomingSIPArcs(sip, getOccurrenceId(literal)): headArc = len(N) == 1 and N[0] == GetOp(newHead) if not set(x).difference(args): # A binding # for q is useful, however, only if it is a binding for an argument of q. bodyPredReplace[literal] = AdornedUniTerm( NormalizeUniterm(literal), [adornment(arg, headArc, x) for arg in args], literal.naf) # For a predicate occurrence with no incoming # arc, the adornment contains only f. For our purposes here, # we do not distinguish between a predicate with such an # adornment and an unadorned predicate (we do in order to support open queries) if literal not in bodyPredReplace and ignoreUnboundDPreds: bodyPredReplace[literal] = AdornedUniTerm( NormalizeUniterm(literal), ['f' for arg in GetArgs(literal)], literal.naf) if hybridPreds2Replace: atomPred = GetOp(adornedHead) if atomPred in hybridPreds2Replace: adornedHead.setOperator(URIRef(atomPred + u'_derived')) for bodAtom in [ bodyPredReplace.get(p, p) for p in iterCondition(sip.sipOrder) ]: bodyPred = GetOp(bodAtom) if bodyPred in hybridPreds2Replace: bodAtom.setOperator(URIRef(bodyPred + u'_derived')) rule = AdornedRule( Clause( And([ bodyPredReplace.get(p, p) for p in iterCondition(sip.sipOrder) ]), adornedHead)) rule.sip = sip return rule
def MagicSetTransformation(factGraph, rules, GOALS, derivedPreds=None, strictCheck=DDL_STRICTNESS_FALLBACK_DERIVED, noMagic=None, defaultPredicates=None): """ Takes a goal and a ruleset and returns an iterator over the rulest that corresponds to the magic set transformation: """ noMagic = noMagic and noMagic or [] magicPredicates = set() # replacement = {} adornedProgram = SetupDDLAndAdornProgram( factGraph, rules, GOALS, derivedPreds=derivedPreds, strictCheck=strictCheck, defaultPredicates=defaultPredicates) newRules = [] for rule in adornedProgram: if rule.isSecondOrder(): import warnings warnings.warn( "Second order rule no supported by GMS: %s" % rule, RuntimeWarning) magicPositions = {} #Generate magic rules for idx, pred in enumerate(iterCondition(rule.formula.body)): # magicBody = [] if isinstance(pred, AdornedUniTerm): # and pred not in magicPredicates: # For each rule r in Pad, and for each occurrence of an adorned # predicate p a in its body, we generate a magic rule defining magic_p a prevPreds = [item for _idx, item in enumerate(rule.formula.body) if _idx < idx] if 'b' not in pred.adornment: import warnings warnings.warn( "adorned predicate w/out any bound arguments (%s in %s)" % (pred, rule.formula), RuntimeWarning) if GetOp(pred) not in noMagic: magicPred = pred.makeMagicPred() magicPositions[idx] = (magicPred, pred) inArcs = [(N, x) for (N, x) in IncomingSIPArcs(rule.sip, getOccurrenceId(pred)) if not set(x).difference(GetArgs(pred))] if len(inArcs) > 1: # If there are several arcs entering qi, we define the # magic rule defining magic_qi in two steps. First, # for each arc Nj --> qi with label cj , we define a # rule with head label_qi_j(cj ). The body of the rule # is the same as the body of the magic rule in the # case where there is a single arc entering qi # (described above). Then the magic rule is defined as # follows. The head is magic_q(0). The body contains # label_qi_j(cj) for all j (that is, for all arcs # entering qi ). # # We combine all incoming arcs into a single list of # (body) conditions for the magic set PrettyPrintRule(rule) SIPRepresentation(rule.sip) print(pred, magicPred) _body = [] additionalRules = [] for idxSip, (N, x) in enumerate(inArcs): newPred = pred.clone() SetOp(newPred, URIRef('%s_label_%s' % (newPred.op, idxSip))) ruleBody = And(buildMagicBody( N, prevPreds, rule.formula.head, derivedPreds)) additionalRules.append(Rule(Clause(ruleBody, newPred))) _body.extend(newPred) # _body.extend(ruleBody) additionalRules.append(Rule(Clause(And(_body), magicPred))) newRules.extend(additionalRules) for i in additionalRules: print(i) raise NotImplementedError() else: for idxSip, (N, x) in enumerate(inArcs): ruleBody = And(buildMagicBody( N, prevPreds, rule.formula.head, derivedPreds, noMagic)) newRule = Rule(Clause(ruleBody, magicPred)) newRules.append(newRule) magicPredicates.add(magicPred) # Modify rules # we modify the original rule by inserting # occurrences of the magic predicates corresponding # to the derived predicates of the body and to the head # If there are no bound arguments in the head, we don't modify the rule idxIncrement = 0 newRule = copy.deepcopy(rule) for idx, (magicPred, origPred) in list(magicPositions.items()): newRule.formula.body.formulae.insert(idx + idxIncrement, magicPred) idxIncrement += 1 if 'b' in rule.formula.head.adornment and GetOp(rule.formula.head) not in noMagic: headMagicPred = rule.formula.head.makeMagicPred() if isinstance(newRule.formula.body, Uniterm): newRule.formula.body = And([headMagicPred, newRule.formula.body]) else: newRule.formula.body.formulae.insert(0, headMagicPred) newRules.append(newRule) if not newRules: newRules.extend(AdditionalRules(factGraph)) for rule in newRules: if rule.formula.body: yield rule
def MagicSetTransformation(factGraph, rules, GOALS, derivedPreds=None, strictCheck=DDL_STRICTNESS_FALLBACK_DERIVED, noMagic=None, defaultPredicates=None): """ Takes a goal and a ruleset and returns an iterator over the rulest that corresponds to the magic set transformation: """ noMagic = noMagic and noMagic or [] magicPredicates = set() # replacement = {} adornedProgram = SetupDDLAndAdornProgram( factGraph, rules, GOALS, derivedPreds=derivedPreds, strictCheck=strictCheck, defaultPredicates=defaultPredicates) newRules = [] for rule in adornedProgram: if rule.isSecondOrder(): import warnings warnings.warn("Second order rule no supported by GMS: %s" % rule, RuntimeWarning) magicPositions = {} #Generate magic rules for idx, pred in enumerate(iterCondition(rule.formula.body)): # magicBody = [] if isinstance(pred, AdornedUniTerm): # and pred not in magicPredicates: # For each rule r in Pad, and for each occurrence of an adorned # predicate p a in its body, we generate a magic rule defining magic_p a prevPreds = [ item for _idx, item in enumerate(rule.formula.body) if _idx < idx ] if 'b' not in pred.adornment: import warnings warnings.warn( "adorned predicate w/out any bound arguments (%s in %s)" % (pred, rule.formula), RuntimeWarning) if GetOp(pred) not in noMagic: magicPred = pred.makeMagicPred() magicPositions[idx] = (magicPred, pred) inArcs = [(N, x) for ( N, x) in IncomingSIPArcs(rule.sip, getOccurrenceId(pred)) if not set(x).difference(GetArgs(pred))] if len(inArcs) > 1: # If there are several arcs entering qi, we define the # magic rule defining magic_qi in two steps. First, # for each arc Nj --> qi with label cj , we define a # rule with head label_qi_j(cj ). The body of the rule # is the same as the body of the magic rule in the # case where there is a single arc entering qi # (described above). Then the magic rule is defined as # follows. The head is magic_q(0). The body contains # label_qi_j(cj) for all j (that is, for all arcs # entering qi ). # # We combine all incoming arcs into a single list of # (body) conditions for the magic set PrettyPrintRule(rule) SIPRepresentation(rule.sip) print(pred, magicPred) _body = [] additionalRules = [] for idxSip, (N, x) in enumerate(inArcs): newPred = pred.clone() SetOp(newPred, URIRef('%s_label_%s' % (newPred.op, idxSip))) ruleBody = And( buildMagicBody(N, prevPreds, rule.formula.head, derivedPreds)) additionalRules.append( Rule(Clause(ruleBody, newPred))) _body.extend(newPred) # _body.extend(ruleBody) additionalRules.append( Rule(Clause(And(_body), magicPred))) newRules.extend(additionalRules) for i in additionalRules: print(i) raise NotImplementedError() else: for idxSip, (N, x) in enumerate(inArcs): ruleBody = And( buildMagicBody(N, prevPreds, rule.formula.head, derivedPreds, noMagic)) newRule = Rule(Clause(ruleBody, magicPred)) newRules.append(newRule) magicPredicates.add(magicPred) # Modify rules # we modify the original rule by inserting # occurrences of the magic predicates corresponding # to the derived predicates of the body and to the head # If there are no bound arguments in the head, we don't modify the rule idxIncrement = 0 newRule = copy.deepcopy(rule) for idx, (magicPred, origPred) in list(magicPositions.items()): newRule.formula.body.formulae.insert(idx + idxIncrement, magicPred) idxIncrement += 1 if 'b' in rule.formula.head.adornment and GetOp( rule.formula.head) not in noMagic: headMagicPred = rule.formula.head.makeMagicPred() if isinstance(newRule.formula.body, Uniterm): newRule.formula.body = And( [headMagicPred, newRule.formula.body]) else: newRule.formula.body.formulae.insert(0, headMagicPred) newRules.append(newRule) if not newRules: newRules.extend(AdditionalRules(factGraph)) for rule in newRules: if rule.formula.body: yield rule