-->

OWL Ontology Predicate Logic with Jena

2019-04-13 12:16发布

问题:

I'm having trouble expressing the following situation in my Ontology:

Suppose I have four people voting and four votes (so there is a one-to-one mapping between vote and voter). People can either vote yes or no. If I know the outcome of three people's votes, I ought to be able to deduce the fourth person's vote.

So to reiterate: John, Bob, Mary, and Carol each vote. Since there are four people there are four votes. The outcome of the vote is a tie (2 yes, and 2 no). Later on the reasoner determines that Bob and John voted no. The reasoner should then be able to deduce that Mary and Carol voted yes.

Currently I am building my ontology using Jena's java api and am inferencing with a Jena reasoner, so I'd rather use rules/semantics supported by Jena.

回答1:

Antoine Zimmerman's answer is right in that this kind of thing is expressible in OWL, but that it requires a bit more work than you might expect, because you're trying to enforce a type of closed world reasoning and default reasoning, whereas OWL makes the open world assumption in which if you don't know something, it's not presumed to be either true or false, just unknown. Once the closure axioms are in place though, this isn't too hard of a scenario to write. I think it's worth working through this problem step by step to see all the axioms that need to be present in order to make this inference, and to do this in OWL DL. You didn't mention Protégé, but it's a very convenient OWL editor, and makes writing these axioms much easier. I'll show the final OWL (in RDF/XML and Turtle) at the end, too.

To represent just one instance, I'd declare a class Voters which has Alice, Bill, Cindy, and Dan as members, and then assert that those individuals are distinct:

Now, to relate each Voter to their vote, we can introduce a hasVote property with domain Voter and the enumerated range containing the strings, "yes", and "no".

We still need something that relates to the four Voters, to tie them together. Conceptually, this is the voting event in which the only participants were Alice, Bill, Cindy, and Dan, and in which each voter has only one vote. Let's introduce a class VotingEvent and an object property hasVoter which relates a VotingEvent to its participants. Now, there is some voting event, for which we'll introduce an individual votingEvent1. We'll assert that its participants are Alice, Bill, Cindy, and Dan, and only those, and that every voter in this event has exactly one vote. We also add two type constraints that say that the event has exactly 2 "yes" voters. This is sufficient, since the requirements that there are only the four enumerated voters, that they are distinct, that each has exactly one vote, and that each vote is either "yes" or "no", and the implicit knowledge that "yes" and "no" are distinct strings, is enough to ensure that the remaining two votes must be "no" votes.

Now, if we finally assert that Alice and Bill cast "yes" votes,

there is enough to infer with a reasoner that Cindy and Dan cast "no" votes, as we can see by running a DL query in Protégé:

Neither the Turtle nor RDF/XML serializations are particularly nice to look at, but I've attached them at the end, for easy copying and pasting. Now, this is a suitable representation for a single voting event, but note that we introduced a voting event in order to have something to which we added the restrictions about the four voters and the values of their votes. However, if there were multiple voting events, and some voters participated in more than one event, the simple restriction that a voter has exactly one vote is problematic because the voter might vote "yes" in one event and "no" in another. The "Voter x cast a vote of y in event z" is a tertiary relation, and really needs to be represented as such if multiple events are going to be present. The W3C Working Group Note, Defining N-ary Relations on the Semantic Web describes some approaches for this, but the basic idea is that you'd define a class whose members represent individuals cast votes, and are related to the voting event, the voter, and the vote cast. You can still write the appropriate restrictions for this kind of reasoning, though they'll be a little bit more complicated, probably involving property chains or nested class expressions.

Turtle Serialization

@prefix :      <http://example.org/voters#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix voters: <http://example.org/voters#> .

voters:Voter  a  owl:Class .

voters:VotingEvent  a  owl:Class .

voters:hasVote  a    owl:DatatypeProperty ;
        rdfs:domain  voters:Voter ;
        rdfs:range   [ a          rdfs:Datatype ;
                       owl:oneOf  [ a          rdf:List ;
                                    rdf:first  "no" ;
                                    rdf:rest   [ a          rdf:List ;
                                                 rdf:first  "yes" ;
                                                 rdf:rest   ()

                                               ]
                                  ]
                     ] .

voters:Dan  a   owl:NamedIndividual , voters:Voter .

<http://example.org/voters>
        a       owl:Ontology .

voters:Alice  a         owl:NamedIndividual , voters:Voter ;
        voters:hasVote  "yes" .

voters:Bill  a          owl:NamedIndividual , voters:Voter ;
        voters:hasVote  "yes" .

voters:Cindy  a  owl:NamedIndividual , voters:Voter .

voters:hasVoter  a   owl:ObjectProperty ;
        rdfs:domain  voters:VotingEvent ;
        rdfs:range   voters:Voter .

voters:votingEvent1  a   owl:NamedIndividual , voters:VotingEvent ;
        a                [ a                         owl:Restriction ;
                           owl:onClass               [ a               owl:Restriction ;
                                                       owl:hasValue    "yes" ;
                                                       owl:onProperty  voters:hasVote
                                                     ] ;
                           owl:onProperty            voters:hasVoter ;
                           owl:qualifiedCardinality  "2"^^xsd:nonNegativeInteger
                         ] ;
        a                [ a                  owl:Restriction ;
                           owl:allValuesFrom  [ a          owl:Class ;
                                                owl:oneOf  ( voters:Dan voters:Bill voters:Cindy voters:Alice )
                                              ] ;
                           owl:onProperty     voters:hasVoter
                         ] ;
        a                [ a                  owl:Restriction ;
                           owl:allValuesFrom  [ a                         owl:Restriction ;
                                                owl:onDataRange           xsd:string ;
                                                owl:onProperty            voters:hasVote ;
                                                owl:qualifiedCardinality  "1"^^xsd:nonNegativeInteger
                                              ] ;
                           owl:onProperty     voters:hasVoter
                         ] ;
        voters:hasVoter  voters:Alice , voters:Bill , voters:Cindy , voters:Dan .

[ a                    owl:AllDifferent ;
  owl:distinctMembers  ( voters:Alice voters:Bill voters:Cindy voters:Dan )
] .

RDF/XML Serialization

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:voters="http://example.org/voters#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:Ontology rdf:about="http://example.org/voters"/>
  <owl:Class rdf:about="http://example.org/voters#Voter"/>
  <owl:Class rdf:about="http://example.org/voters#VotingEvent"/>
  <owl:ObjectProperty rdf:about="http://example.org/voters#hasVoter">
    <rdfs:range rdf:resource="http://example.org/voters#Voter"/>
    <rdfs:domain rdf:resource="http://example.org/voters#VotingEvent"/>
  </owl:ObjectProperty>
  <owl:DatatypeProperty rdf:about="http://example.org/voters#hasVote">
    <rdfs:domain rdf:resource="http://example.org/voters#Voter"/>
    <rdfs:range>
      <rdfs:Datatype>
        <owl:oneOf>
          <rdf:List>
            <rdf:first>no</rdf:first>
            <rdf:rest>
              <rdf:List>
                <rdf:first>yes</rdf:first>
                <rdf:rest rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"/>
              </rdf:List>
            </rdf:rest>
          </rdf:List>
        </owl:oneOf>
      </rdfs:Datatype>
    </rdfs:range>
  </owl:DatatypeProperty>
  <owl:AllDifferent>
    <owl:distinctMembers rdf:parseType="Collection">
      <owl:NamedIndividual rdf:about="http://example.org/voters#Alice">
        <rdf:type rdf:resource="http://example.org/voters#Voter"/>
        <voters:hasVote>yes</voters:hasVote>
      </owl:NamedIndividual>
      <owl:NamedIndividual rdf:about="http://example.org/voters#Bill">
        <rdf:type rdf:resource="http://example.org/voters#Voter"/>
        <voters:hasVote>yes</voters:hasVote>
      </owl:NamedIndividual>
      <owl:NamedIndividual rdf:about="http://example.org/voters#Cindy">
        <rdf:type rdf:resource="http://example.org/voters#Voter"/>
      </owl:NamedIndividual>
      <owl:NamedIndividual rdf:about="http://example.org/voters#Dan">
        <rdf:type rdf:resource="http://example.org/voters#Voter"/>
      </owl:NamedIndividual>
    </owl:distinctMembers>
  </owl:AllDifferent>
  <owl:NamedIndividual rdf:about="http://example.org/voters#votingEvent1">
    <rdf:type rdf:resource="http://example.org/voters#VotingEvent"/>
    <rdf:type>
      <owl:Restriction>
        <owl:onProperty rdf:resource="http://example.org/voters#hasVoter"/>
        <owl:onClass>
          <owl:Restriction>
            <owl:onProperty rdf:resource="http://example.org/voters#hasVote"/>
            <owl:hasValue>yes</owl:hasValue>
          </owl:Restriction>
        </owl:onClass>
        <owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger"
        >2</owl:qualifiedCardinality>
      </owl:Restriction>
    </rdf:type>
    <rdf:type>
      <owl:Restriction>
        <owl:onProperty rdf:resource="http://example.org/voters#hasVoter"/>
        <owl:allValuesFrom>
          <owl:Class>
            <owl:oneOf rdf:parseType="Collection">
              <owl:NamedIndividual rdf:about="http://example.org/voters#Dan"/>
              <owl:NamedIndividual rdf:about="http://example.org/voters#Bill"/>
              <owl:NamedIndividual rdf:about="http://example.org/voters#Cindy"/>
              <owl:NamedIndividual rdf:about="http://example.org/voters#Alice"/>
            </owl:oneOf>
          </owl:Class>
        </owl:allValuesFrom>
      </owl:Restriction>
    </rdf:type>
    <rdf:type>
      <owl:Restriction>
        <owl:onProperty rdf:resource="http://example.org/voters#hasVoter"/>
        <owl:allValuesFrom>
          <owl:Restriction>
            <owl:onProperty rdf:resource="http://example.org/voters#hasVote"/>
            <owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger"
            >1</owl:qualifiedCardinality>
            <owl:onDataRange rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
          </owl:Restriction>
        </owl:allValuesFrom>
      </owl:Restriction>
    </rdf:type>
    <voters:hasVoter rdf:resource="http://example.org/voters#Alice"/>
    <voters:hasVoter rdf:resource="http://example.org/voters#Bill"/>
    <voters:hasVoter rdf:resource="http://example.org/voters#Cindy"/>
    <voters:hasVoter rdf:resource="http://example.org/voters#Dan"/>
  </owl:NamedIndividual>
</rdf:RDF>


回答2:

You do this with an OWL ontology, but it's complicated. First, you have to model the fact that a person only has one vote. Second, you must know that John, Bob, Mary, and Carol voted. You have to know that there have been 2 "yes", and 2 "no". You have to know that Bob and John voted "no", and that they are two people, not one with a pseudonym. You have to know that Mary and Carol are different from John and Bob. And so, in Turtle:

:votes  a  owl:FunctionalProperty .
:John  :votes  "no" .
:Bob  :votes  "no";
    owl:differentFrom  :John .
:Mary  a  [
        owl:onProperty  :votes;
        owl:minCardinality  1
    ];
    owl:differentFrom  :Bob, :John .
:Carol  a  [
        owl:onProperty  :votes;
        owl:minCardinality  1
    ];
    owl:differentFrom  :Bob, :John .
_:someone  a  [ owl:onProperty  :votes; owl:hasValue  "no" ];
    owl:differentFrom  _:someoneelse .
_:someoneelse  a  [ owl:onProperty  :votes; owl:hasValue  "no" ] .
_:anotherone  a  [ owl:onProperty  :votes; owl:hasValue  "yes" ];
    owl:differentFrom  _:anotheroneelse .
_:anotheroneelse  a  [owl:onProperty  :votes; owl:hasValue  "yes" ] .
[ owl:onProperty  :votes; owl:hasValue  "no" ]
    owl:oneOf  ( _:someone _:someoneelse ) .
[ owl:onProperty  :votes; owl:hasValue  "yes" ]
    owl:oneOf  ( _:anotherone _:anotheroneelse ) .

The real difficulty here is to express that there are 2 "yes" and 2 "no". I've made it compact, and so it's not in OWL 2 DL, but it should be possible to make it an OWL 2 DL ontology.

Note that this does not allow modelling multiple polls or ballots. An even more complicated solution would be required (but still doable).