[ 
https://issues.apache.org/jira/browse/RYA-292?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16090788#comment-16090788
 ] 

Jesse Hatfield commented on RYA-292:
------------------------------------

h4. Basic Logic
If A is the intersection of (B, C, D), this means:

bq. (x is an A) *if and only if* (x is a B) AND (x is a C) AND (x is a D) .
Or:
{quote}(1) *If* (x is an A) *then* (x is a B) AND (x is a C) AND (x is a D) .
(2) *If* (x is a B) AND (x is a C) AND (x is a D) *then (x is an A) .{quote}

Implication (1) can be written:
{quote}*If* x is an A *then* x is a B .
*If* x is an A *then* x is a C .
*If* x is an A *then* x is a D .{quote}

Which is equivalent to:
{quote}A subClassOf B .
A subClassOf C .
A subClassOf D .{quote}
(For example, see 
[https://www.w3.org/TR/owl2-profiles/#Reasoning_in_OWL_2_RL_and_RDF_Graphs_using_Rules],
 rule *scm-int* .)

h4. Advanced Cases

A may itself be some bnode, and we may need to answer queries about its 
subclass(es) or superclass(es). For example, when "Mother subClassOf [ 
intersectionOf (Parent, Woman) ]", implication (1) extends to:
{quote}(1) *If* x is a Mother *then* x is a _bnode_ *and therefore* x is a 
Parent and a Woman.{quote}
Using the subclass formulation, this is straightforward: Mother is a subclass 
of the bnode, which in turn is both a subclass of Parent and a subclass of 
Woman. Existing logic handles the implications of the subClassOf graph.

If, on the other hand, we have "[ intersectionOf (Parent, Woman) ] subClassOf 
Mother ", then implication (2) extends to:
{quote}*If* x is a Parent and a Woman *then* x is a _bnode_ *and therefore* x 
is a Mother.{quote}
This means if the query is for instances of type Mother, it isn't sufficient to 
check whether Mother is an intersection, but instead we must check whether 
there is any intersection that should imply Mother, even indirectly. In 
principle, there could be multiple such intersections, if there were multiple 
subclasses, e.g. suppose we define Father similarly and then have some 
superclass shared by both. A query for all the MotherOrFather instances should 
include anything that fits either the Mother intersection or the Father 
intersection.

Theoretically, one could declare multiple intersections for the same type, such 
as "A is the intersection of (B C D); A is the intersection of (E F)."That 
would mean the two intersections represent the same set, and therefore:
{quote}(1) *If* (x is an A) *then* (x is a B) AND (x is a C) AND (x is a D) AND 
(x is an E) AND (x is an F) .
(2a) *If* (x is a B) AND (x is a C) AND (x is a D) *then* (x is an A) AND (x is 
an E) AND (x is an F).
(2b) *If* (x is an E) AND (x is an F) *then* (x is an A) AND (x is a B) AND (x 
is a C) AND (x is a D). {quote}
Implication (1) results in the same subClassOf expressions that would be 
derived from each intersection individually. Implications (2a) and (2b) require 
explicitly recording, for each class in either intersection, that the other 
intersection can imply that class.
h4. Proposed Strategy:

Treat the two implications separately. Use existing subclass logic to handle 
(1) and a new visitor to handle (2).

The InferenceEngine, at schema refresh time, should query for all intersection 
expressions and produce a mapping from individual type to a list of 
intersections that should imply that type. At the same time, it should add the 
subclass relationships to the subclass graph. An intersection expression might 
look something like:
{code}:A owl:intersectionOf _:bnode1 .
_:bnode1 rdf:first :B .
_:bnode1 rdf:rest _:bnode2 .
_:bnode2 rdf:first :C .
_:bnode2 rdf:rest _:bnode3 .
_:bnode3 rdf:first :D .
_:bnode3 rdf:rest rdf:nil .{code}
And the refresh logic:
{code}
intersections <- new Map<Resource, List<Set<Resource>>>()
for (type, head) in query(?type, owl:intersectionOf, ?head):
    if type not in intersections:
        intersections[type] = new List<Set<Resource>>()
    intersection <- new Set<Resource>()
    while (head != rdf:nil):
        intersection += query(head, rdf:first, ?)[0]
        head = query(head, rdf:rest, ?)[0]
    intersections[type].append(intersection)
for (type, intersectionList) in intersections:
    otherTypes <- distinct types in intersections in intersectionList
    for other in otherTypes:
        AddSubClass(type subClassOf other).
        for (intersection in intersectionList unless containing other):
            AddIntersection(intersection implies other)
    for (intersection in intersectionList):
        AddIntersection(intersection implies type)
{code}
At query time, implication (1) will be handled by existing subclass logic. 
Implication (2) will require a new visitor to rewrite appropriate queries. An 
input query {code}SELECT ?x {
    ?x rdf:type :A .
}{code}
should be rewritten to:
{code}SELECT ?x {
    {
        ?x rdf:type :B .
        ?x rdf:type :C .
        ?x rdf:type :D .
    } UNION {
        ?x rdf:type :A .
    }
}{code}
Or in the query algebra, {{StatementPattern(?x, rdf:type, :A)}} should be 
replaced with:
{code}Union(
    Join(
        StatementPattern(?x, rdf:type, :B),
        Join(
            StatementPattern(?x, rdf:type, :C),
            StatementPattern(?x, rdf:type, :D)
        ),
    ),
    StatementPattern(?x, rdf:type, :A)
){code}
Visitor logic might be:
{code}
meet(StatementPattern originalSP):
    if originalSP like (?individual, rdf:type, :c1):  // Assume the type in 
question is explicitly given in the query, not a variable
        intersectionJoins <- new List<InferJoin>()
        for intersection in inferenceEngine.getIntersectionsImplying(c1):
            left <- new InferJoin(intersection.head, intersection.tail.head)
            current <- intersection.tail.tail
            while current != nil:
                left <- new InferJoin(left, current.head)
                current <- current.tail
            intersectionJoins.add(left)
        tree <- InferUnion(intersectionJoins.head, originalSP)
        current <- intersectionJoins.tail
        while (current != nil):
            tree <- InferUnion(node, current.head)
            current <- current.tail
        originalSP.replaceWith(tree)
{code}

> Implement owl:intersectionOf inference
> --------------------------------------
>
>                 Key: RYA-292
>                 URL: https://issues.apache.org/jira/browse/RYA-292
>             Project: Rya
>          Issue Type: Sub-task
>          Components: sail
>            Reporter: Jesse Hatfield
>
> An *{{owl:intersectionOf}}* expression defines the set of resources who 
> belong to all of a particular set of classes.
> A basic implementation, if the ontology states that {{:Mother}} is the 
> intersection of {{:Parent}} and {{:Woman}}, should cause the inference engine 
> to:
> 1. Rewrite query patterns {{?x rdf:type :Mother}} (the intersection type) to 
> check for resources that have both types {{:Parent}} and {{:Woman}} (as well 
> as check for resources that are explicitly stated to be {{:Mother}} s)
> 2. Rewrite query patterns {{?y rdf:type :Parent}} (one of the intersecting 
> sets) to check for resources that are stated to be either {{:Mother}} or 
> {{:Parent}} , since belonging to the intersection type implies membership in 
> the component types. (Equivalent logic applies to {{Woman}} )



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to