dice-group / owlapy

OWLAPY is a Python Framework for creating and manipulating OWL Ontologies.
MIT License
16 stars 1 forks source link

Type Restriction for a filler of OWLDataSomeValuesFrom #30

Closed Demirrr closed 5 months ago

Demirrr commented 5 months ago

Problem:


a=OWLLiteral(3.06)
b=OWLDataProperty(IRI('http://dl-learner.org/mutagenesis#','act'))
c=OWLDataSomeValuesFrom(b,a)

Should the instanciation of c must throw an exception as OWLDataSomeValuesFrom?

Explanation:

OWLDataSomeValuesFrom requires the filler to be an instance of OWLDataRange but a is not an instance of OWLDataRange, i.e., isinstance(a,OWLDataRange)==False

alkidbaci commented 5 months ago

According to the description here: https://www.w3.org/TR/owl2-syntax/#Existential_Quantification_2, the filler for DataSomeValuesFrom should be a data range.

At Data Range section is says:

Datatypes, such as xsd:string or xsd:integer, and literals such as "1"^^xsd:integer, can be used to express data ranges — sets of tuples of literals, where tuples consisting of only one literal are identified with the literal itself.

But if you see Figure 6 there (https://www.w3.org/TR/owl2-syntax/#Data_Ranges), OWLLiteral does not have an inheritance connection with DataRange.

The simplest data ranges are datatypes.

Datatypes do not have a actual value, they just specify if it's an intiger literal or double literal for example.

The DataIntersectionOf, DataUnionOf, and DataComplementOf data ranges provide for the standard set-theoretic operations on data ranges;

The DataOneOf data range consists of exactly the specified set of literals.

If we read the description of DataOneOf it says:

An enumeration of literals DataOneOf( lt1 ... ltn ) contains exactly the explicitly specified literals lti with 1 ≤ i ≤ n.

And now if we get back at the description for DataSomeValuesFrom, it says:

... Such a class expression contains all those individuals that are connected by DPEi to literals lti, 1 ≤ i ≤ n,.

Conclusion - we have the following facts:

If we want to represent DataSomeValuesFrom where the filler should consist of only 1 literal than we can use DataOneOf to represent that literal. OWL 2 specification recommends in this case to use DataHasValue( DPE lt ) which

consists of a data property expression DPE and a literal lt, and it contains all those individuals that are connected by DPE to lt. Each such class expression can be seen as a syntactic shortcut for the class expression DataSomeValuesFrom( DPE DataOneOf( lt ) ).

One may ask why don't we use DataOneOf( lt ) for DataHasValue but we use lt directly. I believe this is an architecture design decision made in purpose because DataHasValue is basically a syntactic shortcut made specifically to replace the long form: DataSomeValuesFrom( DPE DataOneOf( lt )).

If we convert to dl an expression of type OWLDataSomeValuesFrom that has 1 literal as a filler ( of type OWLDataOneOf) and an expression of type OWLDataHasValue and print them, we get the same output. (although this is our implementation)

To finish all this, I think our implementation is fine :)

Demirrr commented 5 months ago

Thank you again for your through answer <3

Given this class definition

class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction):
    def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange):
          ....
  1. filler: OWLDataRange

  2. OWLLiteral(3.06) is not an instance of OWLDataRange

We must ensure that filler must be an instance of OWLDataRange. Therefore, do you think that adding assertions would help us ?

alkidbaci commented 5 months ago

Yes definitely, I'm taking care of it. I just wrote the explanation for the record (although it ended up being a bit longer than expected ^^' )

Demirrr commented 5 months ago

The explanation is very well appreicated :)