Exemplo n.º 1
0
def Th(owlGraph, _class, variable=Variable('X'), position=LHS):
    """
    DLP head (antecedent) knowledge assertional forms (ABox assertions, conjunction of
    ABox assertions, and universal role restriction assertions)
    """
    props = list(set(owlGraph.predicates(subject=_class)))
    if OWL_NS.allValuesFrom in props:
        #http://www.w3.org/TR/owl-semantics/#owl_allValuesFrom
        for s, p, o in owlGraph.triples((_class, OWL_NS.allValuesFrom, None)):
            prop = list(owlGraph.objects(subject=_class, predicate=OWL_NS.onProperty))[0]
            newVar = Variable(BNode())
            body = Uniterm(prop, [variable, newVar], newNss=owlGraph.namespaces())
            for head in Th(owlGraph, o, variable=newVar):
                yield Clause(body, head)
    elif OWL_NS.hasValue in props:
        prop = list(owlGraph.objects(subject=_class, predicate=OWL_NS.onProperty))[0]
        o = first(owlGraph.objects(subject=_class, predicate=OWL_NS.hasValue))
        yield Uniterm(prop, [variable, o], newNss=owlGraph.namespaces())
    elif OWL_NS.someValuesFrom in props:
        #http://www.w3.org/TR/owl-semantics/#someValuesFrom
        for s, p, o in owlGraph.triples((_class, OWL_NS.someValuesFrom, None)):
            prop = list(owlGraph.objects(subject=_class, predicate=OWL_NS.onProperty))[0]
            newVar = BNode()
            yield And([Uniterm(prop, [variable, newVar], newNss=owlGraph.namespaces()),
                        generatorFlattener(Th(owlGraph, o, variable=newVar))])
    elif OWL_NS.intersectionOf in props:
        from FuXi.Syntax.InfixOWL import BooleanClass
        yield And([first(Th(owlGraph, h, variable)) for h in BooleanClass(_class)])
    else:
        #Simple class
        yield Uniterm(RDF.type, [variable,
                                isinstance(_class, BNode) and SkolemizeExistentialClasses(_class) or _class],
                                newNss=owlGraph.namespaces())
Exemplo n.º 2
0
    def extractImp(self, impl):
        body, bodyType, head, headType = self.implications[impl]
        head = first(self.extractPredication(head, headType))
        if bodyType == RIF_NS.And:
            raise
        else:
            body = self.extractPredication(body, bodyType)

        body = And([first(body)]) if len(body) == 1 else And(body)
        return Rule(Clause(body, head), declare=[])
Exemplo n.º 3
0
def Tb(owlGraph, _class, variable=Variable('X')):
    """
    DLP body (consequent knowledge assertional forms (ABox assertions,
    conjunction / disjunction of ABox assertions, and exisential role restriction assertions)
    These are all common EL++ templates for KR
    """
    props = list(set(owlGraph.predicates(subject=_class)))
    if OWL_NS.intersectionOf in props and not isinstance(_class, URIRef):
        for s, p, o in owlGraph.triples((_class, OWL_NS.intersectionOf, None)):
            conj = []
            handleConjunct(conj, owlGraph, o, variable)
            return And(conj)
    elif OWL_NS.unionOf in props and not isinstance(_class, URIRef):
        # http://www.w3.org/TR/owl-semantics/#owl_unionOf
        for s, p, o in owlGraph.triples((_class, OWL_NS.unionOf, None)):
            return Or([
                Tb(owlGraph, c, variable=variable)
                for c in Collection(owlGraph, o)
            ])
    elif OWL_NS.someValuesFrom in props:
        # http://www.w3.org/TR/owl-semantics/#owl_someValuesFrom
        prop = list(
            owlGraph.objects(subject=_class, predicate=OWL_NS.onProperty))[0]
        o = list(
            owlGraph.objects(subject=_class,
                             predicate=OWL_NS.someValuesFrom))[0]
        newVar = Variable(BNode())
        # body = Uniterm(prop, [variable, newVar], newNss=owlGraph.namespaces())
        # head = Th(owlGraph, o, variable=newVar)
        return And([
            Uniterm(prop, [variable, newVar], newNss=owlGraph.namespaces()),
            Tb(owlGraph, o, variable=newVar)
        ])
    elif OWL_NS.hasValue in props:
        # http://www.w3.org/TR/owl-semantics/#owl_hasValue
        # Domain-specific rules for hasValue
        # Can be achieved via pD semantics
        prop = list(
            owlGraph.objects(subject=_class, predicate=OWL_NS.onProperty))[0]
        o = first(owlGraph.objects(subject=_class, predicate=OWL_NS.hasValue))
        return Uniterm(prop, [variable, o], newNss=owlGraph.namespaces())
    elif OWL_NS.complementOf in props:
        return Tc(owlGraph, first(owlGraph.objects(_class,
                                                   OWL_NS.complementOf)))
    else:
        # simple class
        # "Named" Uniterm
        _classTerm = SkolemizeExistentialClasses(_class)
        return Uniterm(RDF.type, [variable, _classTerm],
                       newNss=owlGraph.namespaces())
Exemplo n.º 4
0
def Tc(owlGraph, negatedFormula):
    """
    Handles the conversion of negated DL concepts into a general logic programming
    condition for the body of a rule that fires when the body conjunct
    is in the minimal model
    """
    if (negatedFormula, OWL_NS.hasValue, None) in owlGraph:
        #not ( R value i )
        bodyUniTerm = Uniterm(RDF.type,
                              [Variable("X"),
                               NormalizeBooleanClassOperand(negatedFormula, owlGraph)],
                              newNss=owlGraph.namespaces())

        condition = NormalizeClause(Clause(Tb(owlGraph, negatedFormula),
                                           bodyUniTerm)).body
        assert isinstance(condition, Uniterm)
        condition.naf = True
        return condition
    elif (negatedFormula, OWL_NS.someValuesFrom, None) in owlGraph:
        #not ( R some C )
        binaryRel, unaryRel = Tb(owlGraph, negatedFormula)
        negatedBinaryRel = copy.deepcopy(binaryRel)
        negatedBinaryRel.naf = True
        negatedUnaryRel = copy.deepcopy(unaryRel)
        negatedUnaryRel.naf = True
        return Or([negatedBinaryRel, And([binaryRel, negatedUnaryRel])])
    elif isinstance(negatedFormula, URIRef):
        return Uniterm(RDF.type,
                       [Variable("X"),
                        NormalizeBooleanClassOperand(negatedFormula, owlGraph)],
                       newNss=owlGraph.namespaces(),
                       naf=True)
    else:
        raise UnsupportedNegation("Unsupported negated concept: %s" % negatedFormula)
Exemplo n.º 5
0
def ApplyDemorgans(clause):
    """
    >>> from FuXi.DLP import Clause
    >>> EX_NS = Namespace('http://example.com/')
    >>> ns = {'ex' : EX_NS}
    >>> pred1 = PredicateExtentFactory(EX_NS.somePredicate,newNss=ns)
    >>> pred2 = PredicateExtentFactory(EX_NS.somePredicate2,newNss=ns)
    >>> pred3 = PredicateExtentFactory(EX_NS.somePredicate3,binary=False,newNss=ns)
    >>> pred4 = PredicateExtentFactory(EX_NS.somePredicate4,binary=False,newNss=ns)
    >>> clause = Clause(And([pred1[(Variable('X'),Variable('Y'))],
    ...                      Or([pred2[(Variable('X'),EX_NS.individual1)],
    ...                          pred3[(Variable('Y'))]],naf=True)]),
    ...                 pred4[Variable('X')])
    >>> clause
    ex:somePredicate4(?X) :- And( ex:somePredicate(?X ?Y) not Or( ex:somePredicate2(?X ex:individual1) ex:somePredicate3(?Y) ) )
    >>> ApplyDemorgans(clause)
    >>> clause
    ex:somePredicate4(?X) :- And( ex:somePredicate(?X ?Y) And( not ex:somePredicate2(?X ex:individual1) not ex:somePredicate3(?Y) ) )
    >>> FlattenConjunctions(clause.body)
    >>> clause
    ex:somePredicate4(?X) :- And( ex:somePredicate(?X ?Y) not ex:somePredicate2(?X ex:individual1) not ex:somePredicate3(?Y) )
    """
    from FuXi.DLP import breadth_first, breadth_first_replace
    replacementMap = {}
    for negDisj in [i for i in breadth_first(clause.body) 
                        if isinstance(i,Or) and i.naf]:
        replacementList = []
        for innerTerm in negDisj:
            assert isinstance(i,Uniterm)
            innerTerm.naf = not innerTerm.naf
            replacementList.append(innerTerm)
        replacementMap[negDisj] = And(replacementList)
    for old,new in replacementMap.items():
        list(breadth_first_replace(clause.body,candidate=old,replacement=new))
Exemplo n.º 6
0
    def extractRule(self, rule):
        vars, impl = self.rules[rule]
        body, bodyType, head, headType = self.implications[impl]
        allVars = map(self.extractTerm, Collection(self.graph, vars))
        head = first(self.extractPredication(head, headType))
        if bodyType == RIF_NS.And:
            body = [first(self.extractPredication(
                       i,
                       first(self.graph.objects(i, RDF.type)))
                   ) for i in Collection(self.graph,
                        first(self.graph.objects(body, RIF_NS.formulas)))]

        else:
            body = self.extractPredication(body, bodyType)

        body = And([first(body)]) if len(body) == 1 else And(body)
        return Rule(
            Clause(body, head),
            declare=allVars,
            nsMapping=dict(self.graph.namespaces())
        )
Exemplo n.º 7
0
def NormalizeBody(rule):
    from FuXi.Rete.RuleStore import N3Builtin
    # from itertools import groupby, chain
    newBody = []
    builtIns = []
    if isinstance(rule.formula.body, And):
        for lit in rule.formula.body:
            if isinstance(lit, N3Builtin):
                builtIns.append(lit)
            else:
                newBody.append(lit)
        newBody.extend(builtIns)
        rule.formula.body = And(newBody)
    return rule
Exemplo n.º 8
0
def LloydToporTransformation(clause, fullReduction=True):
    """
    Tautological, common horn logic forms (useful for normalizing
    conjunctive & disjunctive clauses)

    (H ^ H0) :- B                 -> { H  :- B
                                       H0 :- B }
    (H :- H0) :- B                -> H :- B ^ H0

    H :- (B v B0)                 -> { H :- B
                                       H :- B0 }
    """
    assert isinstance(clause, OriginalClause), repr(clause)
    assert isinstance(clause.body, Condition), repr(clause)
    if isinstance(clause.body, Or):
        for atom in clause.body.formulae:
            if hasattr(atom, 'next'):
                atom = first(atom)
            for clz in LloydToporTransformation(
                            NormalizeClause(
                                    Clause(atom,
                                           clause.head)
                            ),
                            fullReduction=fullReduction):
                yield clz
    elif isinstance(clause.head, OriginalClause):
        yield NormalizeClause(Clause(And([clause.body, clause.head.body]), clause.head.head))
    elif fullReduction and (
        (isinstance(clause.head, Exists) and
         isinstance(clause.head.formula, And)) or isinstance(clause.head, And)):
        if isinstance(clause.head, Exists):
            head = clause.head.formula
        elif isinstance(clause.head, And):
            head = clause.head
        for i in head:
            for j in LloydToporTransformation(Clause(clause.body, i),
                                              fullReduction=fullReduction):
                if [i for i in breadth_first(j.head) if isinstance(i, And)]:
                    #Ands in the head need to be further flattened
                    yield PrepareHeadExistential(NormalizeClause(j))
                else:
                    yield PrepareHeadExistential(j)
    else:
        yield clause
Exemplo n.º 9
0
def T(owlGraph, complementExpansions=[], derivedPreds=[]):
    """
    #Subsumption (purely for TBOX classification)
    {?C rdfs:subClassOf ?SC. ?A rdfs:subClassOf ?C} => {?A rdfs:subClassOf ?SC}.
    {?C owl:equivalentClass ?A} => {?C rdfs:subClassOf ?A. ?A rdfs:subClassOf ?C}.
    {?C rdfs:subClassOf ?SC. ?SC rdfs:subClassOf ?C} => {?C owl:equivalentClass ?SC}.

    T(rdfs:subClassOf(C, D))       -> Th(D(y)) :- Tb(C(y))

    T(owl:equivalentClass(C, D)) -> { T(rdfs:subClassOf(C, D)
                                     T(rdfs:subClassOf(D, C) }

    A generator over the Logic Programming rules which correspond
    to the DL  ( unary predicate logic ) subsumption axiom described via rdfs:subClassOf
    """
    for s, p, o in owlGraph.triples((None, OWL_NS.complementOf, None)):
        if isinstance(o, URIRef) and isinstance(s, URIRef):
            headLiteral = Uniterm(
                RDF.type,
                [Variable("X"), SkolemizeExistentialClasses(s)],
                newNss=owlGraph.namespaces())
            yield NormalizeClause(Clause(Tc(owlGraph, o), headLiteral))
    for c, p, d in owlGraph.triples((None, RDFS.subClassOf, None)):
        try:
            yield NormalizeClause(Clause(Tb(owlGraph, c), Th(owlGraph, d)))
        except UnsupportedNegation:
            warnings.warn(
                "Unable to handle negation in DL axiom (%s), skipping" %
                c,  # e.msg,
                SyntaxWarning,
                3)
        # assert isinstance(c, URIRef), "%s is a kind of %s"%(c, d)
    for c, p, d in owlGraph.triples((None, OWL_NS.equivalentClass, None)):
        if c not in derivedPreds:
            yield NormalizeClause(Clause(Tb(owlGraph, c), Th(owlGraph, d)))
        yield NormalizeClause(Clause(Tb(owlGraph, d), Th(owlGraph, c)))
    for s, p, o in owlGraph.triples((None, OWL_NS.intersectionOf, None)):
        try:
            if s not in complementExpansions:
                if s in derivedPreds:
                    warnings.warn(
                        "Derived predicate (%s) is defined via a conjunction (consider using a complex GCI) "
                        % owlGraph.qname(s), SyntaxWarning, 3)
                elif isinstance(
                        s,
                        BNode):  # and (None, None, s) not in owlGraph:# and \
                    # (s, RDFS.subClassOf, None) in owlGraph:
                    # complex GCI, pass over (handled) by Tb
                    continue
                conjunction = []
                handleConjunct(conjunction, owlGraph, o)
                body = And(conjunction)
                head = Uniterm(RDF.type,
                               [Variable("X"),
                                SkolemizeExistentialClasses(s)],
                               newNss=owlGraph.namespaces())
                # O1 ^ O2 ^ ... ^ On => S(?X)
                yield Clause(body, head)
                if isinstance(s, URIRef):
                    # S(?X) => O1 ^ O2 ^ ... ^ On
                    # special case, owl:intersectionOf is a neccessary and sufficient
                    # criteria and should thus work in *both* directions
                    # This rule is not added for anonymous classes or derived
                    # predicates
                    if s not in derivedPreds:
                        yield Clause(head, body)
        except UnsupportedNegation:
            warnings.warn(
                "Unable to handle negation in DL axiom (%s), skipping" %
                s,  # e.msg,
                SyntaxWarning,
                3)

    for s, p, o in owlGraph.triples((None, OWL_NS.unionOf, None)):
        if isinstance(s, URIRef):
            # special case, owl:unionOf is a neccessary and sufficient
            # criteria and should thus work in *both* directions
            body = Or([
                Uniterm(
                    RDF.type,
                    [Variable("X"),
                     NormalizeBooleanClassOperand(i, owlGraph)],
                    newNss=owlGraph.namespaces())
                for i in Collection(owlGraph, o)
            ])
            head = Uniterm(RDF.type, [Variable("X"), s],
                           newNss=owlGraph.namespaces())
            yield Clause(body, head)
    for s, p, o in owlGraph.triples((None, OWL_NS.inverseOf, None)):
        #    T(owl:inverseOf(P, Q))          -> { Q(x, y) :- P(y, x)
        #                                        P(y, x) :- Q(x, y) }
        newVar = Variable(BNode())

        s = SkolemizeExistentialClasses(s) if isinstance(s, BNode) else s
        o = SkolemizeExistentialClasses(o) if isinstance(o, BNode) else o

        body1 = Uniterm(s, [newVar, Variable("X")],
                        newNss=owlGraph.namespaces())
        head1 = Uniterm(o, [Variable("X"), newVar],
                        newNss=owlGraph.namespaces())
        yield Clause(body1, head1)
        newVar = Variable(BNode())
        body2 = Uniterm(o, [Variable("X"), newVar],
                        newNss=owlGraph.namespaces())
        head2 = Uniterm(s, [newVar, Variable("X")],
                        newNss=owlGraph.namespaces())
        yield Clause(body2, head2)
    for s, p, o in owlGraph.triples(
        (None, RDF.type, OWL_NS.TransitiveProperty)):
        # T(owl:TransitiveProperty(P))   -> P(x, z) :- P(x, y) ^ P(y, z)
        y = Variable(BNode())
        z = Variable(BNode())
        x = Variable("X")

        s = SkolemizeExistentialClasses(s) if isinstance(s, BNode) else s

        body = And([
            Uniterm(s, [x, y], newNss=owlGraph.namespaces()),
            Uniterm(s, [y, z], newNss=owlGraph.namespaces())
        ])
        head = Uniterm(s, [x, z], newNss=owlGraph.namespaces())
        yield Clause(body, head)
    for s, p, o in owlGraph.triples((None, RDFS.subPropertyOf, None)):
        # T(rdfs:subPropertyOf(P, Q))     -> Q(x, y) :- P(x, y)
        x = Variable("X")
        y = Variable("Y")

        s = SkolemizeExistentialClasses(s) if isinstance(s, BNode) else s
        o = SkolemizeExistentialClasses(o) if isinstance(o, BNode) else o

        body = Uniterm(s, [x, y], newNss=owlGraph.namespaces())
        head = Uniterm(o, [x, y], newNss=owlGraph.namespaces())

        yield Clause(body, head)
    for s, p, o in owlGraph.triples((None, OWL_NS.equivalentProperty, None)):
        # T(owl:equivalentProperty(P, Q)) -> { Q(x, y) :- P(x, y)
        #                                     P(x, y) :- Q(x, y) }
        x = Variable("X")
        y = Variable("Y")

        s = SkolemizeExistentialClasses(s) if isinstance(s, BNode) else s
        o = SkolemizeExistentialClasses(o) if isinstance(o, BNode) else o

        body = Uniterm(s, [x, y], newNss=owlGraph.namespaces())
        head = Uniterm(o, [x, y], newNss=owlGraph.namespaces())
        yield Clause(body, head)
        yield Clause(head, body)

    # Contribution (Symmetric DL roles)
    for s, p, o in owlGraph.triples(
        (None, RDF.type, OWL_NS.SymmetricProperty)):
        # T(owl:SymmetricProperty(P))   -> P(y, x) :- P(x, y)
        y = Variable("Y")
        x = Variable("X")

        s = SkolemizeExistentialClasses(s) if isinstance(s, BNode) else s

        body = Uniterm(s, [x, y], newNss=owlGraph.namespaces())
        head = Uniterm(s, [y, x], newNss=owlGraph.namespaces())
        yield Clause(body, head)

    for s, p, o in owlGraph.triples_choices((None, [RDFS.range,
                                                    RDFS.domain], None)):

        s = SkolemizeExistentialClasses(s) if isinstance(s, BNode) else s

        if p == RDFS.range:
            # T(rdfs:range(P, D))  -> D(y) := P(x, y)
            x = Variable("X")
            y = Variable(BNode())
            body = Uniterm(s, [x, y], newNss=owlGraph.namespaces())
            head = Uniterm(RDF.type, [y, o], newNss=owlGraph.namespaces())
            yield Clause(body, head)
        else:
            # T(rdfs:domain(P, D)) -> D(x) := P(x, y)
            x = Variable("X")
            y = Variable(BNode())
            body = Uniterm(s, [x, y], newNss=owlGraph.namespaces())
            head = Uniterm(RDF.type, [x, o], newNss=owlGraph.namespaces())
            yield Clause(body, head)
Exemplo n.º 10
0
    def __init__(self, formulae=None, n3Rules=None, nsMapping=None):
        from FuXi.Rete.RuleStore import N3Builtin
        self.nsMapping = nsMapping and nsMapping or {}
        self.formulae = formulae and formulae or []
        if n3Rules:
            from FuXi.DLP import breadth_first
            # Convert a N3 abstract model (parsed from N3) into a RIF BLD
            for lhs, rhs in n3Rules:
                allVars = set()
                for ruleCondition in [lhs, rhs]:
                    for stmt in ruleCondition:
                        if isinstance(stmt, N3Builtin):
                            ExternalFunction(stmt, newNss=self.nsMapping)
                            # print(stmt)
                            # raise
                        allVars.update([
                            term for term in stmt
                            if isinstance(term, (BNode, Variable))
                        ])
                body = [
                    isinstance(term, N3Builtin) and term
                    or Uniterm(list(term)[1],
                               [list(term)[0], list(term)[-1]],
                               newNss=nsMapping) for term in lhs
                ]
                body = len(body) == 1 and body[0] or And(body)
                head = [
                    Uniterm(p, [s, o], newNss=nsMapping) for s, p, o in rhs
                ]
                head = len(head) == 1 and head[0] or And(head)

                # first we identify body variables
                bodyVars = set(
                    reduce(lambda x, y: x + y, [
                        list(extractVariables(i, existential=False))
                        for i in iterCondition(body)
                    ]))
                # then we identify head variables
                headVars = set(
                    reduce(lambda x, y: x + y, [
                        list(extractVariables(i, existential=False))
                        for i in iterCondition(head)
                    ]))

                # then we identify those variables that should (or should not)
                # be converted to skolem terms
                updateDict = dict([(var, BNode()) for var in headVars
                                   if var not in bodyVars])

                for uniTerm in iterCondition(head):

                    def updateUniterm(uterm):
                        newArg = [updateDict.get(i, i) for i in uniTerm.arg]
                        uniTerm.arg = newArg

                    if isinstance(uniTerm, Uniterm):
                        updateUniterm(uniTerm)
                    else:
                        for u in uniTerm:
                            updateUniterm(u)

                exist = [
                    list(extractVariables(i)) for i in breadth_first(head)
                ]
                e = Exists(formula=head,
                           declare=set(reduce(lambda x, y: x + y, exist, [])))
                if reduce(lambda x, y: x + y, exist):
                    head = e
                    assert e.declare, exist

                self.formulae.append(Rule(Clause(body, head), declare=allVars))
Exemplo n.º 11
0
def BuildNaturalSIP(clause,
                    derivedPreds,
                    adornedHead,
                    hybridPreds2Replace=None,
                    ignoreUnboundDPreds=False):
    """
    Natural SIP:

    Informally, for a rule of a program, a sip represents a
    decision about the order in which the predicates of the rule will be evaluated, and how values
    for variables are passed from predicates to other predicates during evaluation

    >>> from functools import reduce
    >>> from io import StringIO
    >>> from FuXi.Rete.RuleStore import SetupRuleStore
    >>> from FuXi.Rete import PROGRAM2
    >>> ruleStore, ruleGraph = SetupRuleStore(StringIO(PROGRAM2))
    >>> ruleStore._finalize()
    >>> fg = Graph().parse(data=PROGRAM2, format='n3')
    >>> from FuXi.Horn.HornRules import Ruleset
    >>> rs = Ruleset(n3Rules=ruleGraph.store.rules, nsMapping=ruleGraph.store.nsMgr)
    >>> for rule in rs: print(rule)
    Forall ?Y ?X ( ex:sg(?X ?Y) :- ex:flat(?X ?Y) )
    Forall ?Y ?Z4 ?X ?Z1 ?Z2 ?Z3 ( ex:sg(?X ?Y) :- And( ex:up(?X ?Z1) ex:sg(?Z1 ?Z2) ex:flat(?Z2 ?Z3) ex:sg(?Z3 ?Z4) ex:down(?Z4 ?Y) ) )
    >>> sip = BuildNaturalSIP(list(rs)[-1], [], None)  #doctest: +SKIP
    >>> for N, x in IncomingSIPArcs(sip, MAGIC.sg): print(N.n3(), x.n3())  #doctest: +SKIP
    ( <http://doi.acm.org/10.1145/28659.28689#up> <http://doi.acm.org/10.1145/28659.28689#sg> <http://doi.acm.org/10.1145/28659.28689#flat> ) ( ?Z3 )
    ( <http://doi.acm.org/10.1145/28659.28689#up> <http://doi.acm.org/10.1145/28659.28689#sg> ) ( ?Z1 )

    >>> sip = BuildNaturalSIP(list(rs)[-1], [MAGIC.sg], None)  #doctest: +SKIP
    >>> list(sip.query('SELECT ?q {  ?prop a magic:SipArc . [] ?prop ?q . }', initNs={%(u)s'magic':MAGIC}))  #doctest: +SKIP
    [rdflib.term.URIRef(%(u)s'http://doi.acm.org/10.1145/28659.28689#sg'), rdflib.term.URIRef(%(u)s'http://doi.acm.org/10.1145/28659.28689#sg')]
    """
    from FuXi.Rete.Magic import AdornedUniTerm
    occurLookup = {}
    boundHead = isinstance(adornedHead,
                           AdornedUniTerm) and 'b' in adornedHead.adornment
    phBoundVars = list(adornedHead.getDistinguishedVariables(varsOnly=True))

    # assert isinstance(clause.head, Uniterm), "Only one literal in the head."

    def collectSip(left, right):
        if isinstance(left, list):
            vars = CollectSIPArcVars(left, right, phBoundVars)
            if not vars and ignoreUnboundDPreds:
                raise InvalidSIPException("No bound variables for %s" % right)
            leftList = Collection(sipGraph, None)
            left = list(set(left))
            [leftList.append(i) for i in [GetOp(ii) for ii in left]]
            left.append(right)
            # arc = SIPGraphArc(leftList.uri, getOccurrenceId(right, occurLookup), vars, sipGraph)
            return left
        else:
            left.isHead = True
            vars = CollectSIPArcVars(left, right, phBoundVars)
            if not vars and ignoreUnboundDPreds:
                raise InvalidSIPException("No bound variables for %s" % right)
            ph = GetOp(left)
            # q = getOccurrenceId(right, occurLookup)
            if boundHead:
                # arc = SIPGraphArc(ph, q, vars, sipGraph, headPassing=boundHead)
                sipGraph.add((ph, RDF.type, MAGIC.BoundHeadPredicate))
                rt = [left, right]
            else:
                rt = [right]
        return rt

    sipGraph = Graph()
    if isinstance(clause.body, And):
        if ignoreUnboundDPreds:
            foundSip = False
            sips = findFullSip(([clause.head], None), clause.body)
            while not foundSip:
                sip = next(sips) if py3compat.PY3 else sips.next()
                try:
                    reduce(collectSip, iterCondition(And(sip)))
                    foundSip = True
                    bodyOrder = sip
                except InvalidSIPException:
                    foundSip = False
        else:
            if first(
                    filter(lambda i: isinstance(i, Uniterm) and i.naf or False,
                           clause.body)):
                # There are negative literals in body, ensure
                # the given sip order puts negated literals at the end
                bodyOrder = first(
                    filter(ProperSipOrderWithNegation,
                           findFullSip(([clause.head], None), clause.body)))
            else:
                bodyOrder = first(
                    findFullSip(([clause.head], None), clause.body))
            assert bodyOrder, "Couldn't find a valid SIP for %s" % clause
            reduce(collectSip, iterCondition(And(bodyOrder)))
        sipGraph.sipOrder = And(bodyOrder[1:])
        # assert validSip(sipGraph), sipGraph.serialize(format='n3')
    else:
        if boundHead:
            reduce(
                collectSip,
                itertools.chain(iterCondition(clause.head),
                                iterCondition(clause.body)))
        sipGraph.sipOrder = clause.body
    if derivedPreds:
        # We therefore generalize our notation to allow
        # more succint representation of sips, in which only arcs entering
        # derived predicates are represented.
        arcsToRemove = []
        collectionsToClear = []
        for N, prop, q in sipGraph.query(
                'SELECT ?N ?prop ?q {  ?prop a magic:SipArc . ?N ?prop ?q . }',
                initNs={u'magic': MAGIC}):
            if occurLookup[q] not in derivedPreds and (
                    occurLookup[q] not in hybridPreds2Replace
                    if hybridPreds2Replace else False):
                arcsToRemove.extend([(N, prop, q), (prop, None, None)])
                collectionsToClear.append(Collection(sipGraph, N))
                # clear bindings collection as well
                bindingsColBNode = first(sipGraph.objects(
                    prop, MAGIC.bindings))
                collectionsToClear.append(
                    Collection(sipGraph, bindingsColBNode))
        for removeSts in arcsToRemove:
            sipGraph.remove(removeSts)
        for col in collectionsToClear:
            col.clear()
    return sipGraph
Exemplo n.º 12
0
def SetupDDLAndAdornProgram(factGraph,
                            rules,
                            GOALS,
                            derivedPreds=None,
                            strictCheck=DDL_STRICTNESS_FALLBACK_DERIVED,
                            defaultPredicates=None,
                            ignoreUnboundDPreds=False,
                            hybridPreds2Replace=None):
    if not defaultPredicates:
        defaultPredicates = [], []
    # _dPredsProvided = bool(derivedPreds)
    if not derivedPreds:
        _derivedPreds = DerivedPredicateIterator(
            factGraph,
            rules,
            strict=strictCheck,
            defaultPredicates=defaultPredicates)
        if not isinstance(derivedPreds, (set, list)):
            derivedPreds = list(_derivedPreds)
        else:
            derivedPreds.extend(_derivedPreds)
    hybridPreds2Replace = hybridPreds2Replace or []
    adornedProgram = AdornProgram(factGraph,
                                  rules,
                                  GOALS,
                                  derivedPreds,
                                  ignoreUnboundDPreds,
                                  hybridPreds2Replace=hybridPreds2Replace)
    if adornedProgram != set([]):
        rt = reduce(lambda l, r: l + r, [
            list(iterCondition(clause.formula.body))
            for clause in adornedProgram
        ])
    else:
        rt = set()
    for hybridPred, adornment in [
        (t, a) for t, a in set([(URIRef(GetOp(term).split('_derived')[0]
                                        ) if GetOp(term).find('_derived') +
                                 1 else GetOp(term), ''.join(term.adornment))
                                for term in rt
                                if isinstance(term, AdornedUniTerm)])
            if t in hybridPreds2Replace
    ]:
        #If there are hybrid predicates, add rules that derived their IDB counterpart
        #using information from the adorned queries to determine appropriate arity
        #and adornment
        hybridPred = URIRef(hybridPred)
        hPred = URIRef(hybridPred + u'_derived')
        if len(adornment) == 1:
            # p_derived^{a}(X) :- p(X)
            body = BuildUnitermFromTuple((Variable('X'), RDF.type, hybridPred))
            head = BuildUnitermFromTuple((Variable('X'), RDF.type, hPred))
        else:
            # p_derived^{a}(X, Y) :- p(X, Y)
            body = BuildUnitermFromTuple(
                (Variable('X'), hybridPred, Variable('Y')))
            head = BuildUnitermFromTuple((Variable('X'), hPred, Variable('Y')))
        _head = AdornedUniTerm(head, list(adornment))
        rule = AdornedRule(Clause(And([body]), _head.clone()))
        rule.sip = Graph()
        adornedProgram.add(rule)

    if factGraph is not None:
        factGraph.adornedProgram = adornedProgram
    return adornedProgram
Exemplo n.º 13
0
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
Exemplo n.º 14
0
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