owlcs / owlapi

OWL API main repository
821 stars 315 forks source link

Functional Syntax Rendering of singleton DisjointClasses axioms is incorrect #151

Closed matthewhorridge closed 10 years ago

matthewhorridge commented 10 years ago

From Peter Patel-Schneider. Reported as a Protege 4.3 bug, but this is due to the OWL API.

It appears that when Protege 4.3 writes out the functional syntax for classes that are disjoint with themselves it incorrectly only puts the classname in the DisjointClasses expression once.

For example,

<owl:Class rdf:about="empty">
       <rdfs:label xml:lang="en">empty</rdfs:label>
       <owl:disjointWith rdf:resource="empty"/>
 </owl:Class>

produces

DisjointClasses(<http://sw.opencyc.org/concept/empty>)

instead of

DisjointClasses(<http://sw.opencyc.org/concept/empty><http://sw.opencyc.org/concept/empty>)

The output is not only semantically incorrect but is also illegal syntax.

This would only be a curiosity except that OpenCyc has a number of these self-disjoint classes, including the purposefully empty class.

I eagerly await a fix so that I can perform reasoning over OpenCyc.

peter

sesuncedu commented 10 years ago

I'm having enough fun just getting opencyc to reason over opencyc (various definition RuleMacros lost their rules when the KB was filtered/ removal module was removed) :-)

On Fri, Apr 11, 2014 at 1:02 AM, Matthew Horridge notifications@github.comwrote:

From Peter Patel-Schneider. Reported as a Protege 4.3 bug, but this is due to the OWL API.

It appears that when Protege 4.3 writes out the functional syntax for classes that are disjoint with themselves it incorrectly only puts the classname in the DisjointClasses expression once.

For example,

empty/rdfs:label /owl:Class produces DisjointClasses(http://sw.opencyc.org/concept/empty) instead of DisjointClasses(http://sw.opencyc.org/concept/emptyhttp://sw.opencyc.org/concept/empty) The output is not only semantically incorrect but is also illegal syntax. This would only be a curiosity except that OpenCyc has a number of these self-disjoint classes, including the purposefully empty class. I eagerly await a fix so that I can perform reasoning over OpenCyc. peter — Reply to this email directly or view it on GitHubhttps://github.com/owlcs/owlapi/issues/151 .
sesuncedu commented 10 years ago

$empty doesn't seem like the right term: that's an individual that

denotes the state of not being full.

$Nothing would seem to be more appropriate here: it has a reformulator

rewriteOf assertion -

(#$rewriteOf #$Nothing (#$CollectionDifferenceFn #$Thing #$Thing))

On Fri, Apr 11, 2014 at 1:27 AM, Simon Spero sesuncedu@gmail.com wrote:

I'm having enough fun just getting opencyc to reason over opencyc (various definition RuleMacros lost their rules when the KB was filtered/ removal module was removed) :-)

On Fri, Apr 11, 2014 at 1:02 AM, Matthew Horridge < notifications@github.com> wrote:

From Peter Patel-Schneider. Reported as a Protege 4.3 bug, but this is due to the OWL API.

It appears that when Protege 4.3 writes out the functional syntax for classes that are disjoint with themselves it incorrectly only puts the classname in the DisjointClasses expression once.

For example,

empty/rdfs:label /owl:Class produces DisjointClasses(http://sw.opencyc.org/concept/empty) instead of DisjointClasses(http://sw.opencyc.org/concept/emptyhttp://sw.opencyc.org/concept/empty) The output is not only semantically incorrect but is also illegal syntax. This would only be a curiosity except that OpenCyc has a number of these self-disjoint classes, including the purposefully empty class. I eagerly await a fix so that I can perform reasoning over OpenCyc. peter — Reply to this email directly or view it on GitHubhttps://github.com/owlcs/owlapi/issues/151 .
ignazio1977 commented 10 years ago

I think the bug is a different one: isn't DisjointClasses one of the axiom types that requires two or more elements in the /set/ of operands?

The output should not be DisjointClasses(empty), it should be empty (pun intended). OpenCyc is not saying what it thinks it's saying, I might say.

Which version of OWLAPI is being used by Protege 4.3? I think I remember it was a version pre 3.4.10. I remember addressing this exact problem in functional syntax - the output of axioms that it cannot parse back.

ignazio1977 commented 10 years ago

Issue #46 is the one that should have fixed this

pfps commented 10 years ago

The problem is that the (silly) axiom foo owl:disjointWith foo is written in the functional syntax in an incorrect fashion, one that is both semantically different and syntactically invalid.

pfps commented 10 years ago

OpenCyc uses empty owl:disjointWith empty to define the empty class, so there is at least one place where the axiom is not so silly.

The problem is that DisjointClasses, and other similar axioms do not take sets. The OWLapi is incorrect in using sets for these axioms, as that changes the meaning of the axioms.

If it is not possible to quickly fix the OWL api correctly, it would be possible to patch the problem by adding owl:Thing and owl:Nothing to any one-element disjoint classes axiom.

ignazio1977 commented 10 years ago

That would be a massive change. I've always understood the specs to say that disjoint classes take sets as arguments. Can you point me in the right direction?

ignazio1977 commented 10 years ago

Regarding rewriting the axioms, I'd be happy with empty subclass of complement (empty) - this would syntactically match what is specified in the specs. It needs to happen in the parsers and/or in the datafactory, though, and will break the interface - from set to collection.

pfps commented 10 years ago

No axioms in OWL 2 take sets as arguments. (Look at 9.1.3 in the OWL 2 SSFSS documentfor an example.) Many axioms do take an arbitrary number of arguments but there is no blanket license to treat these arguments as a set or even as a multi-set. In many cases some of the arguments can be treated asa multi-set and in some cases they can be treated as a set without changing the semantics of the axiom, but this has to be determined on a case-by-case basis.

peter

On 04/11/2014 09:35 AM, Ignazio Palmisano wrote:

That would be a massive change. I've always understood the specs to say that disjoint classes take sets as arguments. Can you point me in the right direction?

— Reply to this email directly or view it on GitHub https://github.com/owlcs/owlapi/issues/151#issuecomment-40223489.

sesuncedu commented 10 years ago

DisjointClasses is defined to take a list of two or more class expressions, all of which are pairwise disjoint.

The semantics are that of a bag rather than a set.

( I see @pfps snuck in ahead of me ).

Cyc defines #$EmptyCollection as the collection of all collections that have no elements, and

each instance of EmptyCollection is disjointWith (q.v.) every collection -- including itself.

$Nothing isa #$EmptyCollection.

$Thing is disjointWith #$Nothing.

So the patch would be correct for Cyc, but not in general; I'm not sure if there is a single correct interpretation for OWL.

$Nothing is defined as a #$rewriteOf (#$CollectionDifferenceFn #$Thing #$Thing)

sesuncedu commented 10 years ago

Guava has MultiSet (which by definition is not a Set).

The API for OWLNaryClassAxiom already has a getClassExpressionsAsList method, which is specified as a convenience method, with the Set returning getClassExpressions() acting as primary.

getClassExpressions could weakened to return Collection without affecting most usages; the only difference between Set and Collection is that Sets enforce uniqueness between elements.

This would still affect typed variables in clients.

A transitional approach: getClassExpressions could be left as is but marked deprecated, with an alias pointing to getUniqueClassExpressions. A new method, getAllClassExpressions could be defined as returning Collection (to avoid the extra duties imposed by being a list). Correcting code local to the owlapi source base would be pretty easy (IntelliJ could do most of the refactoring automatically. This wouldn't fix custom impls like protege, though the changes should not be too hard to implement.

An ugly hack would be to cheat and have the Nary Axiom creators create lying, contract-violating sets that are backed by multisets and which do not enforce the Set contract.

These would either have to either be immutable, or the COW set in the collection factory would have to be FauxSet-aware.

ignazio1977 commented 10 years ago

9.1.3 was one of the sections I was looking at, in fact: (copied here for ease of reference, I know everybody here is familiar with or an editor of the document) http://www.w3.org/TR/owl2-syntax/#Disjoint_Classes

A disjoint classes axiom DisjointClasses( CE1 ... CEn ) states that all of the class expressions CEi, 1 ≤ i ≤ n, are pairwise disjoint; that is, no individual can be at the same time an instance of both CEi and CEj for i ≠ j. An axiom DisjointClasses( CE1 CE2 ) is equivalent to the following axiom:

SubClassOf( CE1 ObjectComplementOf( CE2 ) )

DisjointClasses := 'DisjointClasses' '(' axiomAnnotations ClassExpression ClassExpression { ClassExpression } ')'

In particular, "no individual can be at the same time an instance of both CEi and CEj for i ≠ j."

I've always read this sentence as meaning "the sequence is a set", because the only case CEi and CEj can be equal is when they're both equivalent to owl:Nothing - and if that's the intent of Disjoint(empty), why not use the simpler (IMHO) SubClassOf(empty, owl:Nothing)?

Rant aside, if the set constraint is to be removed then this is a change that reverberates through the whole API. I wanted to relax the Set constraint in the interfaces a while ago (Luigi Iannone opened a SourceForge enhancement request for this, literally years ago), but in the end we decided to stick with the existing interface.

One thing is for sure, I'm not comfortable making this change for 3.5.0. So, short term solution is to have Disjoint|Equivalent|Class|Object|Data|Property be aware of this and actually rewrite these corner case axioms in their syntactically unambiguous and semantically equivalent forms (A subclassof A, or A subclassof Complement(A), as the case might be).

I think that, as a minimal compromise, the renderers could operate this translation, so that roundtripping provides an equivalent, if slightly different looking, ontology. It's not a perfect scenario, because cases like

Disjoint (A, A, B)

will be parsed as

Disjoint (A, B)

and the fact that A is equivalent to owl:Nothing is lost. But, given that the issue is long standing and not too many people seem to lack this functionality, I think it's a decent interim solution, that can be implemented for 3.5.0

pfps commented 10 years ago

I don't think that you can ignore a bit of syntax just because there might be a simpler way of expressing the same meaning.

I don't see anything in the wording there to indicate that CE1 through CEn is anything but a list. To lift this to a multi-set you have to realize that the semantics is independent of the position of the class expressions in the list. However, removing duplicates does change the meaning of the expression, so lifting to a set is not permissible.

If the wording indicated that duplicates were not permitted, then it would be possible to use a set, but there is nothing to prevent duplications.

peter

On 04/11/2014 12:53 PM, Ignazio Palmisano wrote:

9.1.3 was one of the sections I was looking at, in fact: (copied here for ease of reference, I know everybody here is familiar with or an editor of the document) http://www.w3.org/TR/owl2-syntax/#Disjoint_Classes

A disjoint classes axiom DisjointClasses( CE1 ... CEn ) states that all of the class expressions CEi, 1 ≤ i ≤ n, are pairwise disjoint; that is, no individual can be at the same time an instance of both CEi and CEj for i ≠ j. An axiom DisjointClasses( CE1 CE2 ) is equivalent to the following axiom:

SubClassOf( CE1 ObjectComplementOf( CE2 ) )

DisjointClasses := 'DisjointClasses' '(' axiomAnnotations ClassExpression ClassExpression { ClassExpression } ')'

In particular, "no individual can be at the same time an instance of both CEi and CEj for i ≠ j."

I've always read this sentence as meaning "the sequence is a set", because the only case CEi and CEj can be equal is when they're both equivalent to owl:Nothing - and if that's the intent of Disjoint(empty), why not use the simpler (IMHO) SubClassOf(empty, owl:Nothing)?

Rant aside, if the set constraint is to be removed then this is a change that reverberates through the whole API. I wanted to relax the Set constraint in the interfaces a while ago (Luigi Iannone opened a SourceForge enhancement request for this, literally years ago), but in the end we decided to stick with the existing interface.

One thing is for sure, I'm not comfortable making this change for 3.5.0. So, short term solution is to have Disjoint|Equivalent|Class|Object|Data|Property be aware of this and actually rewrite these corner case axioms in their syntactically unambiguous and semantically equivalent forms (A subclassof A, or A subclassof Complement(A), as the case might be).

I think that, as a minimal compromise, the renderers could operate this translation, so that roundtripping provides an equivalent, if slightly different looking, ontology. It's not a perfect scenario, because cases like

Disjoint (A, A, B)

will be parsed as

Disjoint (A, B)

and the fact that A is equivalent to owl:Nothing is lost. But, given that the issue is long standing and not too many people seem to lack this functionality, I think it's a decent interim solution, that can be implemented for 3.5.0

— Reply to this email directly or view it on GitHub https://github.com/owlcs/owlapi/issues/151#issuecomment-40246741.

ignazio1977 commented 10 years ago

We need to reconcile the treatment of the collections of elements in axioms with the following too, which seems to say duplicate entities in expressions /should/ be removed:

http://www.w3.org/TR/owl2-syntax/#Structural_Specification

Sets written in one of the exchange syntaxes (e.g., XML or RDF/XML) are not necessarily expected to be duplicate free. Duplicates should be eliminated when ontology documents written in such syntaxes are converted into instances of the UML classes of the structural specification.

An ontology written in functional-style syntax can contain the following class expression:

ObjectUnionOf( a:Person a:Animal a:Animal ) During parsing, this expression should be "flattened" to the following expression:

ObjectUnionOf( a:Person a:Animal )

pfps commented 10 years ago

Ooh. I had forgotten about that part of the specification.

The bug is in the OWL specs. I'll see if I can come up with a fix that requires only small implementation changes.

petter

On 04/11/2014 01:11 PM, Ignazio Palmisano wrote:

We need to reconcile the treatment of the collections of elements in axioms with the following too, which seems to say duplicate entities in expressions /should/ be removed:

http://www.w3.org/TR/owl2-syntax/#Structural_Specification

Sets written in one of the exchange syntaxes (e.g., XML or RDF/XML) are not necessarily expected to be duplicate free. Duplicates should be eliminated when ontology documents written in such syntaxes are converted into instances of the UML classes of the structural specification.

An ontology written in functional-style syntax can contain the following class expression:

ObjectUnionOf( a:Person a:Animal a:Animal ) During parsing, this expression should be "flattened" to the following expression:

ObjectUnionOf( a:Person a:Animal )

— Reply to this email directly or view it on GitHub https://github.com/owlcs/owlapi/issues/151#issuecomment-40248315.

pfps commented 10 years ago

I think that changing the translation for x owl:disjointWith x would fix over 99% of this issue.

Is this done by the OWL API?

If so, is changing this translation to SubClassOf(x owl:Nothing) something that can be easily done?

I have submitted amessage to public-owl-comments on the issue.

peter

On 04/11/2014 01:33 PM, Peter F. Patel-Schneider wrote:

Ooh. I had forgotten about that part of the specification.

The bug is in the OWL specs. I'll see if I can come up with a fix that requires only small implementation changes.

petter

On 04/11/2014 01:11 PM, Ignazio Palmisano wrote:

We need to reconcile the treatment of the collections of elements in axioms with the following too, which seems to say duplicate entities in expressions /should/ be removed:

http://www.w3.org/TR/owl2-syntax/#Structural_Specification

Sets written in one of the exchange syntaxes (e.g., XML or RDF/XML) are not necessarily expected to be duplicate free. Duplicates should be eliminated when ontology documents written in such syntaxes are converted into instances of the UML classes of the structural specification.

An ontology written in functional-style syntax can contain the following class expression:

ObjectUnionOf( a:Person a:Animal a:Animal ) During parsing, this expression should be "flattened" to the following expression:

ObjectUnionOf( a:Person a:Animal )

— Reply to this email directly or view it on GitHub https://github.com/owlcs/owlapi/issues/151#issuecomment-40248315.

ignazio1977 commented 10 years ago

It should be doable, I'll look into it.

sesuncedu commented 10 years ago
  1. Duplicate elements in EquivalentClasses are eliminable.
  2. The same applies to Equivalent...Properties.
  3. The collection of expressions in SameIndividual is necessarily a set (since the RDF mapping does not involve SEQ
  4. It is inconsistent to have duplicate individuals in a DifferentIndividual list.
  5. Roles Chains are intrinsically lists.
  6. Disjointness is where things become tricky.

We can replace self-disjointness with equivalence to owl:Nothing. Ax + DisjointClasses'(CE1) = Ax Ax + DisjointClasses'(CE_1...CE_i...CE_j...CE_n) = Ax + EquivalentClasses(CE_i, owl:Nothing) + DisjointClasses'(CE_1...CE_n - CE_i) if i <=1 <=n, j <=1 <=n, i != j, CE_i == CE_j etc. I don't think there are any profiles allow disjointness but not owl:Nothing?

  1. DisjointUnionOf is defined in terms of DisjointClasses
  2. Disjoint...Properties can be handled by analogy , except that RL forbids bottom..property (but you can sort of fake it with a pair of disjoint classes, an equiv class, and some sticky-backed plastic. )
ignazio1977 commented 10 years ago

Good summary, Simon.

I think using DisjointProperty(P,P) would put the ontology outside RL because it is semantically equivalent to the bottom property, and using P would then have the same computational consequences - or, if the reasoner does not support anything outside RL, be ignored/throw exceptions/throw a wobbly.

sesuncedu commented 10 years ago

Need to preserve this a AS/FSS error for WHO-WG.