Search code examples
annotationsrdfowlontologyreification

How to serialize an annotated axiom to the RDF form?


Let's take the axiom SubClassOf( DataAllValuesFrom( <d> xsd:boolean ) ObjectSomeValuesFrom( <o> owl:Thing ) Annotation( rdfs:comment "comm"^^xsd:string ) ).

What should this axiom look like in the form of RDF?

If I understand the specification correctly, there is one and only one way:

Example 1:

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

<o>     a       owl:ObjectProperty .

[ a                      owl:Axiom ;
  rdfs:comment           "comm" ;
  owl:annotatedProperty  rdfs:subClassOf ;
  owl:annotatedSource    [ a                  owl:Restriction ;
                           rdfs:subClassOf    _:c2 ;
                           owl:allValuesFrom  xsd:boolean ;
                           owl:onProperty     <d>
                         ] ;
  owl:annotatedTarget    _:c2
] .

<d>     a       owl:DatatypeProperty .

_:c2    a                   owl:Restriction ;
        owl:onProperty      <o> ;
        owl:someValuesFrom  owl:Thing .

But, it suddenly turned out that there are people who understand the specification in a different way. And the axiom above may or even must be written as follows:

Example 2:

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

<o>     a       owl:ObjectProperty .

<d>     a       owl:DatatypeProperty .

[ a                      owl:Axiom ;
  rdfs:comment           "comm" ;
  owl:annotatedProperty  rdfs:subClassOf ;
  owl:annotatedSource    [ a                   owl:Restriction ;
                           rdfs:subClassOf     [ a                  owl:Restriction ;
                                                 owl:allValuesFrom  owl:Thing ;
                                                 owl:onProperty     <o>
                                               ] ;
                           owl:onProperty      <d> ;
                           owl:someValuesFrom  xsd:boolean
                         ] ;
  owl:annotatedTarget    [ a                  owl:Restriction ;
                           owl:allValuesFrom  owl:Thing ;
                           owl:onProperty     <o>
                         ]
] .

So, the question is, who is right? Which example is correct?

In my opinion, the second RDF (example 2) violates understanding of RDF reification and data connectivity. But I could not convey this to the opponent. I have arguments based on the specification (that may be offered as an answer later), but these arguments turned out to be untenable in his eyes, so I appeal to a wide range of specialists here to get new arguments, or, maybe, to improve my own vision of the concept: nobody (with except of me) has said yet that the example 1 is the only correct way.
So it would be nice, having the specification, obtain a proof that the first (or the second) example is correct.

If I understood correctly, my opponent appeals to the following phrase from the specification:
In the mapping, each generated blank node (i.e., each blank node that does not correspond to an anonymous individual) is fresh in each application of a mapping rule.. Which, he thinks, means that super-class ObjectSomeValuesFrom( <o> owl:Thing ) must get b-node twice while writing to RDF.
How to proof that this is not true (or true)?

Thank you.


Solution

  • So, since no answers yet, here is my own, which is based on my understanding of the official specification https://www.w3.org/TR/owl2-mapping-to-rdf/. Any comments and improvements are welcome.


    1. Introduction

    The spec defines only the operators T(E) and TANN(ann, y), where ann is Annotation( AP av ), Eand y are some objects. The spec also says: The definition of the operator T uses the operator TANN in order to translate annotations. For the operations that are described in the section 2.1 Translation of Axioms without Annotations and the section 2.3 Translation of Axioms with Annotations there are no own names. The operator TANN is defined in Table 2, section 2.2 Translation of Annotations, but it is annotation for annotation, which is producing a b-node with root triple _:x rdf:type owl:Annotation. The operator that creates top-level annotations with the root triple _: x rdf: type owl: Axiom is described in the section 2.3.1 Axioms that Generate a Main Triple, but also does not have a proper name. And, in sake of demonstration, I'm going to introduce a new name for this "operator": ANN. Note 1: do not confuse it with the function ANN from the section 3.2.2 Parsing of Annotations - we don't need that last thing; this answer is only about mapping, not parsing. Note 2: I am not writing my own spec, I am just trying to explain my vision using the new abbreviation. In general case this injection may not be correct, but for demonstration purposes, I think it is OK.

    Also, let's consider the axiom SubClassOf as an operator with two operands. It is described in the Table 1 from the section 2.1 Translation of Axioms without Annotations like this:

    SubClassOf( CE1 CE2 ) = T(CE1) rdfs:subClassOf T(CE2) .
    

    Let's also consider an overloaded operator SubClassOf with two operands and vararg of annotations. The SubClassOf( CE1 CE2 annotations { n > 1 } ) is defined in the section 2.3.1 Axioms that Generate a Main Triple like the following:

    s p xlt .
    _:x rdf:type owl:Axiom .
    _:x owl:annotatedSource s .
    _:x owl:annotatedProperty p .
    _:x owl:annotatedTarget xlt .
    TANN(annotation1, _:x)
    ...
    TANN(annotationm, _:x) 
    

    For simplicity let's dwell on one case when there is only one top-level annotation. So, that operator is SubClassOf( CE1, CE2, ann) and it looks like this:

    T(CE1) rdfs:subClassOf T(CE2) .
    ANN(CE1, CE2, rdfs:subClassOf, ann) .
    

    This is a new operator ANN, which is similar to TANN, but accepts two operands, annotation and constant, that defines the predicate. It produces the root triple _:x rdf:type owl:Axiom and all other triples are similar to the triples for the operator TANN in the example above, so ANN(s, xlt, p, ann) is :

    _:x rdf:type owl:Axiom .
    _:x owl:annotatedSource s .
    _:x owl:annotatedProperty p .
    _:x owl:annotatedTarget xlt .
    TANN(ann, _:x)
    

    2. An ontology without annotations.

    Now lets consider the example from the question where the first operand is DataAllValuesFrom and the second is ObjectSomeValuesFrom:

    SubClassOf( DataAllValuesFrom( <d> xsd:boolean ) ObjectSomeValuesFrom( <o> owl:Thing ) ) .
    

    In TURTLE it would look like this:

    <d>     a       owl:DatatypeProperty .
    <o>     a       owl:ObjectProperty .
    [ rdf:type owl:Restriction ;
                            owl:onProperty <d> ;
                            owl:allValuesFrom xsd:boolean ;
                            rdfs:subClassOf [ rdf:type owl:Restriction ;
                                              owl:onProperty <o> ;
                                              owl:someValuesFrom owl:Thing
                                            ]
                          ] ;
    

    Or the same ontology in NTRIPLES syntax:

    <d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
    <o> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
    _:c1 <http://www.w3.org/2000/01/rdf-schema#subClassOf> _:c2 .
    _:c1 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:c1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    _:c1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:c2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:c2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:c2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    

    SubClassOf is an axiom that generate a main triple (see the section 2.3.1 Axioms that Generate a Main Triple). So, the main triple (s p xlt) here is _:c1 <http://www.w3.org/2000/01/rdf-schema#subClassOf> _:c2, where s (the subject, in the example DataAllValuesFrom( <d> xsd:boolean )) is _:c1, p (the predicate) is rdfs:subClassOf, and xlt (xlt stands for a blank node, an IRI, or a literal, here it is the object, in the example ObjectSomeValuesFrom( <o> owl:Thing )) is _:c2.

    Note, in ONT-API such TURTLE can be generated by the following code:

    OntModel m = OntModelFactory.createModel().setNsPrefixes(OntModelFactory.STANDARD);
    m.createDataAllValuesFrom(m.createDataProperty("d"), m.getDatatype(XSD.xboolean))
        .addSuperClass(m.createObjectSomeValuesFrom(m.createObjectProperty("o"), 
        m.getOWLThing()));
    m.write(System.out, "ttl");
    

    3. Behaving of the operator T.

    The spec says: In the mapping, each generated blank node (i.e., each blank node that does not correspond to an anonymous individual) is fresh in each application of a mapping rule.. I believe this is only about the operator T. This statement is roughly matched what is said in the Parsing OWL, Structure Sharing, OWL1 spec: In practice, this means that blank nodes (i.e. those with no name) which are produced during the transformation and represent arbitrary expressions in the abstract syntax form should not be "re-used".. In ordinary case it is not a problem neither for ONT-API nor OWL-API, all these things behave similarly. The following code produces identical RDF both for OWL-API (default impl) and ONT-API (with the OWL-API interfaces used):

    OWLOntologyManager m = OntManagers.createONT();
    OWLDataFactory df = m.getOWLDataFactory();
    OWLClassExpression ce = df.getOWLObjectComplementOf(df.getOWLThing());
    OWLOntology o = m.createOntology();            
    o.add(df.getOWLSubClassOfAxiom(ce, ce));
    o.saveOntology(OntFormat.TURTLE.createOwlFormat(), System.out);
    

    For the two equal class expressions ObjectComplementOf( owl:Thing ) which are operands of SubClassOf( CE1, CE2 ) there would be two different b-nodes. So, nobody disputes the fact that in OWL there is no objects sharing.
    But, in my opinion, this must not be apply to the relationship between the axiom and its annotations, which is the case of the operator ANN, see the next paragraph.


    4.1 An annotated axiom that generate a main triple. Reification with SPO.

    Now lets add an annotation Annotation( rdfs:comment "comm" ) to the SubClassOf( DataAllValuesFrom( <d> xsd:boolean ) ObjectSomeValuesFrom( <o> owl:Thing ) ) (see previous paragraph 2) in a manner that I think is the only true. Remember, that the operator SubClassOf(CE1, CE2, ann) generates the following ttl:

    T(CE1) rdfs:subClassOf T(CE2) .
    ANN(CE1, CE2, rdfs:subClassOf, ann) .
    

    or

    s p xlt .
    _:x rdf:type owl:Axiom .
    _:x owl:annotatedSource s .
    _:x owl:annotatedProperty p .
    _:x owl:annotatedTarget xlt .
    TANN(ann, _:x)
    

    Here, the triple s p xlt is the result of applying the operator SubClassOf(CE1, CE2). From the Table 2, section 2.2 Translation of Annotations, the operator TANN(Annotation( AP av ), _:x) for Annotation( rdfs:comment "comm"^^xsd:string ) will give the triple _:x rdfs:comment "comm"^^xsd:string, so we have (SubClassOf(CE1, CE2, Annotation( rdfs:comment "comm"^^xsd:string ))):

    s p xlt .
    _:x rdf:type owl:Axiom .
    _:x owl:annotatedSource s .
    _:x owl:annotatedProperty p .
    _:x owl:annotatedTarget xlt .
    _:x rdfs:comment "comm"^^xsd:string .
    

    The triple s p xlt here is _:c1 rdfs:subClassOf _:c2 (see paragraph 2); so finally we get the following annotated axiom:

    _:c1 rdfs:subClassOf _:c2 .
    _:x rdfs:comment "comm"^^xsd:string .
    _:x rdf:type owl:Axiom .
    _:x owl:annotatedSource _:c1 .
    _:x owl:annotatedProperty rdfs:subClassOf .
    _:x owl:annotatedTarget _:c2 .
    

    The full ontology (without ontology id) in NTRIPLES syntax would look like this:

    <o> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
    <d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
    _:x <http://www.w3.org/2000/01/rdf-schema#comment> "comm" .
    _:x <http://www.w3.org/2002/07/owl#annotatedTarget> _:c2 .
    _:x <http://www.w3.org/2002/07/owl#annotatedProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> .
    _:x <http://www.w3.org/2002/07/owl#annotatedSource> _:c1 .
    _:x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Axiom> .
    _:c2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:c2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:c2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:c1 <http://www.w3.org/2000/01/rdf-schema#subClassOf> _:c2 .
    _:c1 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:c1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    _:c1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    

    Or the same in TURTLE:

    @prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix owl:   <http://www.w3.org/2002/07/owl#> .
    @prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
    @prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
    
    <o>     a       owl:ObjectProperty .
    
    [ a                      owl:Axiom ;
      rdfs:comment           "comm" ;
      owl:annotatedProperty  rdfs:subClassOf ;
      owl:annotatedSource    [ a                  owl:Restriction ;
                               rdfs:subClassOf    _:c2 ;
                               owl:allValuesFrom  xsd:boolean ;
                               owl:onProperty     <d>
                             ] ;
      owl:annotatedTarget    _:c2
    ] .
    
    <d>     a       owl:DatatypeProperty .
    
    _:c2    a                   owl:Restriction ;
            owl:onProperty      <o> ;
            owl:someValuesFrom  owl:Thing .
    

    The triple _:c1 rdfs:subClassOf _:c2 (SPO) is present in the graph and has its reification:

    _:x owl:annotatedTarget _:c2 .
    _:x owl:annotatedProperty rdfs:subClassOf .
    _:x owl:annotatedSource _:c1 .
    

    Note, that this ontology can be generated by the following code:

    OntModel m = OntModelFactory.createModel().setNsPrefixes(OntModelFactory.STANDARD);
    m.createDataAllValuesFrom(m.createDataProperty("d"), m.getDatatype(XSD.xboolean))
            .addSubClassOfStatement(m.createObjectSomeValuesFrom(m.createObjectProperty("o"), m.getOWLThing()))
            .annotate(m.getRDFSComment(), "comm");
    m.write(System.out, "ttl");
    System.out.println(".......");
    m.write(System.out, "nt");
    

    4.2 An annotated axiom that generate a main triple. Reification with (S*)P(O*).

    Well, the spec also says that In the mapping, each generated blank node (i.e., each blank node that does not correspond to an anonymous individual) is fresh in each application of a mapping rule. This is about the operator T, but not for the operators TANN, ANN, SubClassOf(CE1, CE2) or SubClassOf(CE1, CE2, ann). But SubClassOf operators consist of T and ANN(TANN), so they must also implicitly generate a blank node for each operands. I remind that the operator SubClassOf(CE1, CE2, ann) originally (see p.1) looks like following:

    T(CE1) rdfs:subClassOf T(CE2) .
    ANN(CE1, CE2, rdfs:subClassOf, ann) .
    

    But it is still not fully clear what should actually happen with its second part - the operator ANN(CE1, CE2, rdfs:subClassOf, ann). Let's take my opponent's assumption (as far as I understand it), that the class expressions must not be shared even within a whole axiom including all its hierarchy-tree of annotations. This is definitely true for the operator SubClassOf(CE1, CE2), and wrong for the operator TANN, and the subject of controversy for the operator ANN (that includes TANN). But for a sake of experiment lets assume that the rule also must be applicable to the ANN operands. So, the SubClassOf(CE1, CE2, ann) is now defined as follows:

    SubClassOf(CE1, CE2) .
    ANN(T(CE1), T(CE2), rdfs:subClassOf, ann) .
    

    or

    T(CE1) rdfs:subClassOf T(CE2) .
    ANN(T(CE1), T(CE2), rdfs:subClassOf, ann) .
    

    The SubClassOf(CE1, CE2) will give the following NTRIPLES (see p.2):

    <d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
    <o> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
    _:c2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:c2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:c2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:c1 <http://www.w3.org/2000/01/rdf-schema#subClassOf> _:c2 .
    _:c1 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:c1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    _:c1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    

    Here, the b-node _:c1 corresponds to the class expression DataAllValuesFrom( <d> xsd:boolean ), and the b-node _:c2 corresponds to the ObjectSomeValuesFrom( <o> owl:Thing ).

    Then we do T in ANN for the subject (the first operand T(CE1)):

    _:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:b1 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:b1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    

    and for the object (the second operand T(CE2)):

    _:b2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:b2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    

    And print ANN itself:

    _:x <http://www.w3.org/2000/01/rdf-schema#comment> "comm" .
    _:x <http://www.w3.org/2002/07/owl#annotatedTarget> _:b2 .
    _:x <http://www.w3.org/2002/07/owl#annotatedProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> .
    _:x <http://www.w3.org/2002/07/owl#annotatedSource> _:b1 .
    _:x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Axiom> .
    

    Notice, that now we have fresh b-nodes for CE1 and CE2 (_:b1 and _:b2 - respectively), and have a reference in annotation (_:x) for these two nodes. Inside the annotation graph-structure there are _:b1, _:b2, not _:c1,_:c2, just because we first apply the operator T to the input class expression, and only then pass the result further into the operator ANN.

    The full ontology would be as the following (just concatenate all parts above) (NTRIPLES):

    <o> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
    <d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
    _:c2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:c2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:c2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:c1 <http://www.w3.org/2000/01/rdf-schema#subClassOf> _:c2 .
    _:c1 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:c1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    _:c1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:x <http://www.w3.org/2000/01/rdf-schema#comment> "comm" .
    _:x <http://www.w3.org/2002/07/owl#annotatedTarget> _:b2 .
    _:x <http://www.w3.org/2002/07/owl#annotatedProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> .
    _:x <http://www.w3.org/2002/07/owl#annotatedSource> _:b1 .
    _:x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Axiom> .
    _:b2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:b2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:b1 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:b1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    
    

    Or the same in TURTLE:

    @prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix owl:   <http://www.w3.org/2002/07/owl#> .
    @prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
    @prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
    
    <o>     a       owl:ObjectProperty .
    
    [ a                  owl:Restriction ;
      rdfs:subClassOf    [ a                   owl:Restriction ;
                           owl:onProperty      <o> ;
                           owl:someValuesFrom  owl:Thing
                         ] ;
      owl:allValuesFrom  xsd:boolean ;
      owl:onProperty     <d>
    ] .
    
    <d>     a       owl:DatatypeProperty .
    
    [ a                      owl:Axiom ;
      rdfs:comment           "comm" ;
      owl:annotatedProperty  rdfs:subClassOf ;
      owl:annotatedSource    [ a                  owl:Restriction ;
                               owl:allValuesFrom  xsd:boolean ;
                               owl:onProperty     <d>
                             ] ;
      owl:annotatedTarget    [ a                   owl:Restriction ;
                               owl:onProperty      <o> ;
                               owl:someValuesFrom  owl:Thing
                             ]
    ] .
    
    

    As you can see, the triple _:c1 rdfs:subClassOf _:c2 (SPO) is present in the graph, but has no reification. Instead, there is a reification for the triple _:b1 rdfs:subClassOf _:b2 ((S*)P(O*)), which does not actually exist in the graph:

    _:x owl:annotatedTarget _:b2 .
    _:x owl:annotatedProperty rdfs:subClassOf .
    _:x owl:annotatedSource _:b1 .
    

    Since the triple _:b1 rdfs:subClassOf _:b2 does not exist, then, in my opinion, this exercise demonstrates invalid behavior.


    4.3 An annotated axiom that generate a main triple by OWL-API. Reification with SP(O*).

    As you might guess, my opponent defends the current behavior of OWL-API (v5.1.11). So let's see what OWL-API does. The code to generate:

    OWLOntologyManager man = OntManagers.createOWL();
    OWLDataFactory df = man.getOWLDataFactory();
    OWLAxiom a = df.getOWLSubClassOfAxiom(df.getOWLDataSomeValuesFrom(df.getOWLDataProperty("d"),
            df.getBooleanOWLDatatype()),
            df.getOWLObjectAllValuesFrom(df.getOWLObjectProperty("o"), df.getOWLThing()),
            Collections.singletonList(df.getRDFSComment("comm")));
    OWLOntology o = man.createOntology();
    o.add(a);
    o.saveOntology(new TurtleDocumentFormat(), System.out);
    

    NTRIPLES (the Ontology ID is omitted):

    <o> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
    <d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#DatatypeProperty> .
    _:u <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:u <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:u <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:x <http://www.w3.org/2000/01/rdf-schema#comment> "comm" .
    _:x <http://www.w3.org/2002/07/owl#annotatedTarget> _:u .
    _:x <http://www.w3.org/2002/07/owl#annotatedProperty> <http://www.w3.org/2000/01/rdf-schema#subClassOf> .
    _:x <http://www.w3.org/2002/07/owl#annotatedSource> _:c1 .
    _:x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Axiom> .
    _:c1 <http://www.w3.org/2000/01/rdf-schema#subClassOf> _:c2 .
    _:c1 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://www.w3.org/2001/XMLSchema#boolean> .
    _:c1 <http://www.w3.org/2002/07/owl#onProperty> <d> .
    _:c1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    _:c2 <http://www.w3.org/2002/07/owl#allValuesFrom> <http://www.w3.org/2002/07/owl#Thing> .
    _:c2 <http://www.w3.org/2002/07/owl#onProperty> <o> .
    _:c2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
    

    The original TURTLE:

    @prefix owl: <http://www.w3.org/2002/07/owl#> .
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix xml: <http://www.w3.org/XML/1998/namespace> .
    @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    @base <http://www.w3.org/2002/07/owl#> .
    
    [ rdf:type owl:Ontology
     ] .
    
    #################################################################
    #    Object Properties
    #################################################################
    
    ###  o
    <o> rdf:type owl:ObjectProperty .
    
    
    #################################################################
    #    Data properties
    #################################################################
    
    ###  d
    <d> rdf:type owl:DatatypeProperty .
    
    
    #################################################################
    #    General axioms
    #################################################################
    
    [ rdf:type owl:Axiom ;
      owl:annotatedSource [ rdf:type owl:Restriction ;
                            owl:onProperty <d> ;
                            owl:someValuesFrom xsd:boolean ;
                            rdfs:subClassOf [ rdf:type owl:Restriction ;
                                              owl:onProperty <o> ;
                                              owl:allValuesFrom owl:Thing
                                            ]
                          ] ;
      owl:annotatedProperty rdfs:subClassOf ;
      owl:annotatedTarget [ rdf:type owl:Restriction ;
                            owl:onProperty <o> ;
                            owl:allValuesFrom owl:Thing
                          ] ;
      rdfs:comment "comm"
    ] .
    
    
    ###  Generated by the OWL API (version 5.1.11) https://github.com/owlcs/owlapi/
    

    And the reformatted TURTLE (again, without ontology id):

    @prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix owl:   <http://www.w3.org/2002/07/owl#> .
    @prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
    @prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
    
    <o>     a       owl:ObjectProperty .
    
    <d>     a       owl:DatatypeProperty .
    
    [ a                      owl:Axiom ;
      rdfs:comment           "comm" ;
      owl:annotatedProperty  rdfs:subClassOf ;
      owl:annotatedSource    [ a                   owl:Restriction ;
                               rdfs:subClassOf     [ a                  owl:Restriction ;
                                                     owl:allValuesFrom  owl:Thing ;
                                                     owl:onProperty     <o>
                                                   ] ;
                               owl:onProperty      <d> ;
                               owl:someValuesFrom  xsd:boolean
                             ] ;
      owl:annotatedTarget    [ a                  owl:Restriction ;
                               owl:allValuesFrom  owl:Thing ;
                               owl:onProperty     <o>
                             ]
    ] .
    

    As you can see, the triple _:c1 rdfs:subClassOf _:c2 (SPO) is present in the graph, but has no reification, just like in the previous paragraph (p4.2). Instead, there is a reification for the triple _:c1 rdfs:subClassOf _:u (SP(O*)), which does not actually exist in the graph:

    _:x owl:annotatedTarget _:u .
    _:x owl:annotatedProperty rdfs:subClassOf .
    _:x owl:annotatedSource _:c1 .
    

    Also note, for this example, the operator SubClassOf(CE1, CE2, ann) must be as follows:

    T(CE1) rdfs:subClassOf T(CE2) .
    ANN(CE1, T(CE2), rdfs:subClassOf, ann) .
    

    here, the first operand is passed as is, but for the second there is T-transformation, which produces a fresh b-node.

    Since the triple _:c1 rdfs:subClassOf _:u does not exist in the whole graph, this example also demonstrates wrong behavior. So, in my opinion OWL-API (v5.1.11) does not produce correct RDF in the case an annotated axiom consists of anonymous expressions.


    5. Conclusion and notes.

    • So, why both specs prohibit reusing b-nodes for a mapping? Well, I see the only one explanation - the authors want axioms to be atomic. If some axiom's components were shared, then it is not possible to separately turn off/on desired axioms while reasoning.
    • Does the example from the paragraph 4.1 violate this principle? No, the annotation still belongs to the only axiom, and cannot refer to another.
    • The examples from the paragraphs 4.2, 4.3 are wrong: the corresponding reified statements do not really exist. But, as far as I can see, my opponent, defending the correctness of 4.3, gives arguments that lead to the correctness of 4.2. I think, this strange fact is also an implicit proof of correctness 4.1.
    • The operator SubClassOf(CE1, CE2, ann) from the example 4.3 is unsymmetric. There are no any clues in the spec which may lead to such an unbalanced outcome. Why there is a transformation T for the second operand, but not for the first - this is a question.
    • The source (a comment in github issue): https://github.com/owlcs/owlapi/issues/874#issuecomment-527399645