x in A or x in B (or in both)#

Context: https://www.dublincore.org/specifications/openwemi/ , i.e. the following files:

This document mainly addresses the issue dcmi/openwemi#123.

Starting point#

The figure below basically suggests:

yellow arrows:

  • IF we have a relation x instantiates z

  • THEN z is a Work; or z is an Expression; or z is a Manifestation; or both, or all of the above.

green arrows:

  • IF we have a relation p manifests q

  • THEN q is a Work; or q is an Expression; or both.

(Note that we do not have a natural language like xor, but a math like inclusive or.)

Source: https://www.dublincore.org/specifications/openwemi/specification/

We do have two interpretations of the green dashed line:

  • (1) q is an element of Work; or q is an element of Expression; or both.

  • (2) q is an element of the union of Work and Expression

Similarly we do have two interpretations of the yellow dashed line:

  • (1) z is an element of Work; or z is an element of Expression; or z is an element of Manifestation; or both, or all of the above.

  • (2) z is an element of the union of Work, Expression and Manifestation.

Note again: we have not an exclusive xor, but an inclusive or.

The image above and also the non normative english text of the open-WEMI Spec suggest (1). And in the normative ttl-file the definition of openwemi:instantiates it is given: > "A relationship asserted from an Item to a Manifestation, an Expression, or a Work."@en

However, the normative turtle file https://dcmi.github.io/openwemi/ns/openWEMI.ttl in fact implements (2).

Our contribution#

  • reconstruct (parts of) the normative ttl file

    • omit all not necessary or redundant triples

    • turn implicit classes to explicit named classes

We tried to vizualize the reconstructed class hierarchy. This is an intermediary result (comments are welcome):

dcmi-open-wemi.pdf, dcmi-open-wemi.odg

open WEMI reconstructed#

import rdflib
import owlrl
from IPython.display import display, Markdown
prefixes = """
@prefix : <http://example.org/ns#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix openwemi: <https://dcmi.github.io/openwemi/ns#> .
"""

TBox, terminology box, ontology in the narrower sense:

ttl = prefixes + """
#
# T-Box
#

# WEMI 
# Work OR Expression OR Manifestation OR Item
# i.e. unionOf(Work, Expression, Manifestation, Item)
# i.e. same as openwemi:endeavor

:WEMI a owl:Class;
    owl:unionOf (
      :Work
      :Expression
      :Manifestation
      :Item ) .


# WEM ... Work OR Expression OR Manifestation

# from https://dcmi.github.io/openwemi/ns/openWEMI.ttl :
#openwemi:instantiates
#  a rdf:Property ;
#  rdfs:label "instantiates"@en ;
#  rdfs:comment "An Endeavor that instantiates a Manifestation, an Expression or a Work."@en ;
#  rdfs:isDefinedBy openwemi: ;
#  rdfs:subPropertyOf dct:relation ;
#  rdfs:domain openwemi:Item ;
#  dct:description "A relationship asserted from an Item to a Manifestation, an Expression, or a Work."@en ;
#  rdfs:range [
#    a owl:Class ;
#    owl:unionOf (
#      openwemi:Work
#      openwemi:Expression
#      openwemi:Manifestation
#    )
#  ] .

:instantiates
  a rdf:Property ;
  rdfs:domain :Item ;
  rdfs:range :WEM . 

:instantiatedBy
  a rdf:Property ;
  owl:inverseOf :instantiates .
  # given in openWEMI.ttl, but redundant:
  # rdfs:range :Item ; 
  # rdfs:domain :WEM .

:WEM a owl:Class;
    owl:unionOf (
      :Work
      :Expression
      :Manifestation) .

# trivial subclass relationship
# however, we *do* have to assert it explicitly,
# for it cannot be inferred by our owlrl reasoner 
# (i.e. profile OWL2 RL)
:WEM rdfs:subClassOf :WEMI . 

:manifests
  a rdf:Property ;
  rdfs:domain :Manifestation ;
  rdfs:range :WE .      

# WE ... Work OR Expression

:WE a owl:Class;
    owl:unionOf (
      :Work
      :Expression ) .

# assert manually; cannot be inferred in profile OWL2 RL
:WE rdfs:subClassOf :WEM .
:WEM rdfs:subClassOf :WEMI .
"""

ABox, assertion box: We add some example instances, i.e. xxx and zzz (we use variables which are aligned with rule rdfs3):

ttl += """
#
# A-Box
#

# x_1 == xxx, z_1 == zzz in rule rdfs3
:x_1 :instantiates   :z_1 .
:z_2 :instantiatedBy :x_2 .

:p_3 :manifests :q_3 .

:w_1 a :Work . 
"""

After inferencing the resulting graphs may be pretty long. We define a utility function to select only the interesting paragraphs.

def focus(focus_curie_list, ttl, sort = False):
    """Split a text file into paragraps. 
    Return only these paragraphs which contain at least one string from focus_curie_list."""

    par_list = [ paragraph for paragraph in ttl.split("\n\n") \
                         if any( [ focus_curie in paragraph for focus_curie in focus_curie_list ] ) ]
    if sort:
        result = "\n\n".join( sorted(par_list)  )
    else:
        result = "\n\n".join( par_list )
    return result
def multi_focus(focus_curie_list, graph_dict):
    """apply focus() on a dict of graphs and print the result side by side"""
    result = {}
    print(f"{focus_curie_list=}\n")
    for graph_name, graph in graph_dict.items():
        ttl = graph.serialize()
        result[graph_name] = focus(focus_curie_list, ttl, sort=True)
        print(f"""=== Graph {graph_name}: {len(graph_name)} triples ===\n\n{result[graph_name]}\n""")
    return None
gd = {} # graph dict, dict of graphs

gd['original'] = rdflib.Graph().parse(data= ttl)
gd['with_inferencing'] = rdflib.Graph().parse( data=gd['original'].serialize() )  # deep copy

# infer maximum set of triples 
owlrl.DeductiveClosure(owlrl.OWLRL_Semantics,
    axiomatic_triples = False).expand(gd['with_inferencing'])

# for graph_name, graph in gd.items(): print(f"{graph_name=} has {len(graph)} triples")
interesting = [ ":x_1" ]
multi_focus(interesting, gd )
focus_curie_list=[':x_1']

=== Graph original: 8 triples ===

:x_1 :instantiates :z_1 .

=== Graph with_inferencing: 16 triples ===

:x_1 a :Item,
        :WEMI,
        owl:Thing ;
    :instantiates :z_1 ;
    owl:sameAs :x_1 .

:z_1 a :WEM,
        :WEMI,
        owl:Thing ;
    :instantiatedBy :x_1 ;
    owl:sameAs :z_1 .
interesting = [ ":p_", ":q_" ]
multi_focus(interesting, gd )
focus_curie_list=[':p_', ':q_']

=== Graph original: 8 triples ===

:p_3 :manifests :q_3 .

=== Graph with_inferencing: 16 triples ===

:p_3 a :Manifestation,
        :WEM,
        :WEMI,
        owl:Thing ;
    :manifests :q_3 ;
    owl:sameAs :p_3 .

:q_3 a :WE,
        :WEM,
        :WEMI,
        owl:Thing ;
    owl:sameAs :q_3 .
interesting = [ ":w_" ]
multi_focus(interesting, gd )
focus_curie_list=[':w_']

=== Graph original: 8 triples ===

:w_1 a :Work .

=== Graph with_inferencing: 16 triples ===

:w_1 a :WE,
        :WEM,
        :WEMI,
        :Work,
        owl:Thing ;
    owl:sameAs :w_1 .

Background Knowledge#

Sets in Python#

Background knowledge 1: set intersection and union, here by example in Python.

Example: We have the set of some even numbers and some prime numbers.

even = {2,4,6,8}
prime = {2,3,5,7}

We build a new set, the intersection:

even_AND_prime = even & prime
even_AND_prime
{2}

and the union set:

even_OR_prime = even | prime
even_OR_prime
{2, 3, 4, 5, 6, 7, 8}

Add 100 to the union set (but not to the respective subsets):

z = 100
even_OR_prime.add(z)
even_OR_prime
{2, 3, 4, 5, 6, 7, 8, 100}

Now 100 is in (i.e. an element of) the union set, but not in any of it’s subsets:

z in even_OR_prime, z in even, z in prime
(True, False, False)

Rule rdfs3, Semantics of rdfs:range#

rdfs3, https://www.w3.org/TR/rdf11-mt/#patterns-of-rdfs-entailment-informative

Rule rdfs3:

IF an RDF graph contains the triples

  • aaa rdfs:range xxx

AND

  • yyy aaa zzz

THEN we can entail the triple

  • zzz rdf:type xxx

Test 1: multiple rdfs:range statements#

rdfs3, https://www.w3.org/TR/rdf-schema/#ch_range

Where P has more than one rdfs:range property, then the resources denoted by the objects of triples with predicate P are instances of all the classes stated by the rdfs:range properties.

ttl_test_rdfs3 = prefixes + """
# IF
:aaa rdfs:range :xxx1 .
:aaa rdfs:range :xxx2 .

# AND
:yyy :aaa :zzz .

# THEN these triples should be inferred:
# :zzz rdf:type :xxx1 .
# :zzz rdf:type :xxx2 .
"""
test_rdfs3 = {} # graph dict, dict of graphs

test_rdfs3['original'] = rdflib.Graph().parse(data= ttl_test_rdfs3)
test_rdfs3['with_inferencing'] = rdflib.Graph().parse( data=test_rdfs3['original'].serialize() )  # deep copy

# infer maximum set of triples 
owlrl.DeductiveClosure(owlrl.OWLRL_Semantics,
    axiomatic_triples = False).expand(test_rdfs3['with_inferencing'])

interesting = [ "zzz" ]
multi_focus(interesting, test_rdfs3 )
focus_curie_list=['zzz']

=== Graph original: 8 triples ===

:yyy :aaa :zzz .

=== Graph with_inferencing: 16 triples ===

:yyy :aaa :zzz ;
    owl:sameAs :yyy .

:zzz a :xxx1,
        :xxx2 ;
    owl:sameAs :zzz .

We get :zzz a :xxx1, :xxx2: QED!

Test 2: union of multiple range classes#

In the WEMI ttl file we do not have multiple ranges. Instead we have a union of more than one classes:

openwemi:instantiates
  rdfs:range [
    owl:unionOf (
      openwemi:Work
      openwemi:Expression
      openwemi:Manifestation
    )
  ] .

The term openwemi:instantiates rdfs:range [ owl:unionOf ( ... ) ] has an anonymous class in object position. However, it is trivial to replace it with a named class:

openwemi:instantiates
  rdfs:range :WEM .

:WEM owl:unionOf (
      openwemi:Work
      openwemi:Expression
      openwemi:Manifestation
    ) .

We apply rdfs3 to the WEMI ttl file, i.e. aaa = instantiates, xxx = WEM with WEM = unionOf(Work, Expression, Manifestation):

  • IF :instantiates rdfs:range :WEM .

  • AND :yyy :instantiates :zzz .

  • THEN :zzz rdf:type :WEM .

Again we test our understanding based on the original definition of rule rdfs3:

rdfs3, https://www.w3.org/TR/rdf11-mt/#patterns-of-rdfs-entailment-informative

Rule rdfs3:

  • IF: aaa rdfs:range xxx

  • AND: yyy aaa zzz .

  • THEN: zzz rdf:type xxx .

ttl2_test_rdfs3 = prefixes + """
@prefix : <http://example.org/ns#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix openwemi: <https://dcmi.github.io/openwemi/ns#> .

# IF
:aaa rdfs:range :xxx .
:xxx owl:unionOf (:xxx1 :xxx2) .

# AND
:yyy :aaa :zzz .

# THEN it should be inferred:
#:zzz a :xxx .

# NOTE: It should be NOT inferred sth. like this:
#:zzz a :xxx1 .
#:zzz a :xxx2 .
"""
# print(ttl2_test_rdfs3)
test2_rdfs3 = {} # graph dict, dict of graphs

test2_rdfs3['original'] = rdflib.Graph().parse(data= ttl2_test_rdfs3)
test2_rdfs3['with_inferencing'] = rdflib.Graph().parse( data=test2_rdfs3['original'].serialize() )  # deep copy

# infer maximum set of triples 
owlrl.DeductiveClosure(owlrl.OWLRL_Semantics,
    axiomatic_triples = False).expand(test2_rdfs3['with_inferencing'])

interesting = ["zzz" ]
multi_focus(interesting, test2_rdfs3 )
focus_curie_list=['zzz']

=== Graph original: 8 triples ===

:yyy :aaa :zzz .

=== Graph with_inferencing: 16 triples ===

:yyy :aaa :zzz ;
    owl:sameAs :yyy .

:zzz a :xxx ;
    owl:sameAs :zzz .

We (only) get :zzz a :xxx: QED!

The full graphs#

print(gd['original'].serialize())
@prefix : <http://example.org/ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

:instantiatedBy a rdf:Property ;
    owl:inverseOf :instantiates .

:manifests a rdf:Property ;
    rdfs:domain :Manifestation ;
    rdfs:range :WE .

:p_3 :manifests :q_3 .

:w_1 a :Work .

:x_1 :instantiates :z_1 .

:z_2 :instantiatedBy :x_2 .

:WE a owl:Class ;
    rdfs:subClassOf :WEM ;
    owl:unionOf ( :Work :Expression ) .

:WEMI a owl:Class ;
    owl:unionOf ( :Work :Expression :Manifestation :Item ) .

:instantiates a rdf:Property ;
    rdfs:domain :Item ;
    rdfs:range :WEM .

:WEM a owl:Class ;
    rdfs:subClassOf :WEMI ;
    owl:unionOf ( :Work :Expression :Manifestation ) .
print(gd['with_inferencing'].serialize())
@prefix : <http://example.org/ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:p_3 a :Manifestation,
        :WEM,
        :WEMI,
        owl:Thing ;
    :manifests :q_3 ;
    owl:sameAs :p_3 .

:w_1 a :WE,
        :WEM,
        :WEMI,
        :Work,
        owl:Thing ;
    owl:sameAs :w_1 .

rdf:HTML a rdfs:Datatype ;
    owl:sameAs rdf:HTML .

rdf:PlainLiteral a rdfs:Datatype ;
    owl:sameAs rdf:PlainLiteral .

rdf:XMLLiteral a rdfs:Datatype ;
    owl:sameAs rdf:XMLLiteral .

rdf:first owl:sameAs rdf:first .

rdf:langString a rdfs:Datatype ;
    owl:sameAs rdf:langString .

rdf:rest owl:sameAs rdf:rest .

rdf:type owl:sameAs rdf:type .

rdfs:Literal a rdfs:Datatype ;
    owl:sameAs rdfs:Literal .

rdfs:comment a owl:AnnotationProperty ;
    owl:sameAs rdfs:comment .

rdfs:domain owl:sameAs rdfs:domain .

rdfs:isDefinedBy a owl:AnnotationProperty ;
    owl:sameAs rdfs:isDefinedBy .

rdfs:label a owl:AnnotationProperty ;
    owl:sameAs rdfs:label .

rdfs:range owl:sameAs rdfs:range .

rdfs:seeAlso a owl:AnnotationProperty ;
    owl:sameAs rdfs:seeAlso .

rdfs:subClassOf owl:sameAs rdfs:subClassOf .

rdfs:subPropertyOf owl:sameAs rdfs:subPropertyOf .

xsd:NCName a rdfs:Datatype ;
    owl:sameAs xsd:NCName .

xsd:NMTOKEN a rdfs:Datatype ;
    owl:sameAs xsd:NMTOKEN .

xsd:Name a rdfs:Datatype ;
    owl:sameAs xsd:Name .

xsd:anyURI a rdfs:Datatype ;
    owl:sameAs xsd:anyURI .

xsd:base64Binary a rdfs:Datatype ;
    owl:sameAs xsd:base64Binary .

xsd:boolean a rdfs:Datatype ;
    owl:sameAs xsd:boolean .

xsd:byte a rdfs:Datatype ;
    owl:sameAs xsd:byte .

xsd:date a rdfs:Datatype ;
    owl:sameAs xsd:date .

xsd:dateTime a rdfs:Datatype ;
    owl:sameAs xsd:dateTime .

xsd:dateTimeStamp a rdfs:Datatype ;
    owl:sameAs xsd:dateTimeStamp .

xsd:decimal a rdfs:Datatype ;
    owl:sameAs xsd:decimal .

xsd:double a rdfs:Datatype ;
    owl:sameAs xsd:double .

xsd:float a rdfs:Datatype ;
    owl:sameAs xsd:float .

xsd:hexBinary a rdfs:Datatype ;
    owl:sameAs xsd:hexBinary .

xsd:int a rdfs:Datatype ;
    owl:sameAs xsd:int .

xsd:integer a rdfs:Datatype ;
    owl:sameAs xsd:integer .

xsd:language a rdfs:Datatype ;
    owl:sameAs xsd:language .

xsd:long a rdfs:Datatype ;
    owl:sameAs xsd:long .

xsd:negativeInteger a rdfs:Datatype ;
    owl:sameAs xsd:negativeInteger .

xsd:nonNegativeInteger a rdfs:Datatype ;
    owl:sameAs xsd:nonNegativeInteger .

xsd:nonPositiveInteger a rdfs:Datatype ;
    owl:sameAs xsd:nonPositiveInteger .

xsd:normalizedString a rdfs:Datatype ;
    owl:sameAs xsd:normalizedString .

xsd:positiveInteger a rdfs:Datatype ;
    owl:sameAs xsd:positiveInteger .

xsd:short a rdfs:Datatype ;
    owl:sameAs xsd:short .

xsd:string a rdfs:Datatype ;
    owl:sameAs xsd:string .

xsd:time a rdfs:Datatype ;
    owl:sameAs xsd:time .

xsd:token a rdfs:Datatype ;
    owl:sameAs xsd:token .

xsd:unsignedByte a rdfs:Datatype ;
    owl:sameAs xsd:unsignedByte .

xsd:unsignedInt a rdfs:Datatype ;
    owl:sameAs xsd:unsignedInt .

xsd:unsignedLong a rdfs:Datatype ;
    owl:sameAs xsd:unsignedLong .

xsd:unsignedShort a rdfs:Datatype ;
    owl:sameAs xsd:unsignedShort .

owl:backwardCompatibleWith a owl:AnnotationProperty ;
    owl:sameAs owl:backwardCompatibleWith .

owl:deprecated a owl:AnnotationProperty ;
    owl:sameAs owl:deprecated .

owl:equivalentClass owl:sameAs owl:equivalentClass .

owl:equivalentProperty owl:sameAs owl:equivalentProperty .

owl:incompatibleWith a owl:AnnotationProperty ;
    owl:sameAs owl:incompatibleWith .

owl:inverseOf owl:sameAs owl:inverseOf .

owl:priorVersion a owl:AnnotationProperty ;
    owl:sameAs owl:priorVersion .

owl:sameAs owl:sameAs owl:sameAs .

owl:unionOf owl:sameAs owl:unionOf .

owl:versionInfo a owl:AnnotationProperty ;
    owl:sameAs owl:versionInfo .

:q_3 a :WE,
        :WEM,
        :WEMI,
        owl:Thing ;
    owl:sameAs :q_3 .

:x_1 a :Item,
        :WEMI,
        owl:Thing ;
    :instantiates :z_1 ;
    owl:sameAs :x_1 .

:x_2 a :Item,
        :WEMI,
        owl:Thing ;
    :instantiates :z_2 ;
    owl:sameAs :x_2 .

:z_1 a :WEM,
        :WEMI,
        owl:Thing ;
    :instantiatedBy :x_1 ;
    owl:sameAs :z_1 .

:z_2 a :WEM,
        :WEMI,
        owl:Thing ;
    :instantiatedBy :x_2 ;
    owl:sameAs :z_2 .

:instantiatedBy a rdf:Property ;
    rdfs:subPropertyOf :instantiatedBy ;
    owl:equivalentProperty :instantiatedBy ;
    owl:inverseOf :instantiates ;
    owl:sameAs :instantiatedBy .

:manifests a rdf:Property ;
    rdfs:domain :Manifestation,
        :WEM,
        :WEMI,
        owl:Thing ;
    rdfs:range :WE,
        :WEM,
        :WEMI,
        owl:Thing ;
    rdfs:subPropertyOf :manifests ;
    owl:equivalentProperty :manifests ;
    owl:sameAs :manifests .

owl:Nothing a owl:Class ;
    rdfs:subClassOf :WE,
        :WEM,
        :WEMI,
        owl:Nothing,
        owl:Thing ;
    owl:equivalentClass owl:Nothing ;
    owl:sameAs owl:Nothing .

:Expression rdfs:subClassOf :WE,
        :WEM,
        :WEMI,
        owl:Thing ;
    owl:sameAs :Expression .

:instantiates a rdf:Property ;
    rdfs:domain :Item,
        :WEMI,
        owl:Thing ;
    rdfs:range :WEM,
        :WEMI,
        owl:Thing ;
    rdfs:subPropertyOf :instantiates ;
    owl:equivalentProperty :instantiates ;
    owl:sameAs :instantiates .

rdf:Property owl:sameAs rdf:Property .

() owl:sameAs () .

:Item rdfs:subClassOf :WEMI,
        owl:Thing ;
    owl:sameAs :Item .

:Manifestation rdfs:subClassOf :WEM,
        :WEMI,
        owl:Thing ;
    owl:sameAs :Manifestation .

:Work rdfs:subClassOf :WE,
        :WEM,
        :WEMI,
        owl:Thing ;
    owl:sameAs :Work .

owl:Class owl:sameAs owl:Class .

:WE a owl:Class ;
    rdfs:subClassOf :WE,
        :WEM,
        :WEMI,
        owl:Thing ;
    owl:equivalentClass :WE ;
    owl:sameAs :WE ;
    owl:unionOf _:nf7c16469ece44a5db0d447cd588522abb1 .

owl:AnnotationProperty owl:sameAs owl:AnnotationProperty .

:WEM a owl:Class ;
    rdfs:subClassOf :WEM,
        :WEMI,
        owl:Thing ;
    owl:equivalentClass :WEM ;
    owl:sameAs :WEM ;
    owl:unionOf _:nf7c16469ece44a5db0d447cd588522abb7 .

:WEMI a owl:Class ;
    rdfs:subClassOf :WEMI,
        owl:Thing ;
    owl:equivalentClass :WEMI ;
    owl:sameAs :WEMI ;
    owl:unionOf _:nf7c16469ece44a5db0d447cd588522abb3 .

owl:Thing a owl:Class ;
    rdfs:subClassOf owl:Thing ;
    owl:equivalentClass owl:Thing ;
    owl:sameAs owl:Thing .

rdfs:Datatype owl:sameAs rdfs:Datatype .

_:nf7c16469ece44a5db0d447cd588522abb1 rdf:first :Work ;
    rdf:rest _:nf7c16469ece44a5db0d447cd588522abb2 ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb1 .

_:nf7c16469ece44a5db0d447cd588522abb2 rdf:first :Expression ;
    rdf:rest () ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb2 .

_:nf7c16469ece44a5db0d447cd588522abb3 rdf:first :Work ;
    rdf:rest _:nf7c16469ece44a5db0d447cd588522abb4 ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb3 .

_:nf7c16469ece44a5db0d447cd588522abb4 rdf:first :Expression ;
    rdf:rest _:nf7c16469ece44a5db0d447cd588522abb5 ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb4 .

_:nf7c16469ece44a5db0d447cd588522abb5 rdf:first :Manifestation ;
    rdf:rest _:nf7c16469ece44a5db0d447cd588522abb6 ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb5 .

_:nf7c16469ece44a5db0d447cd588522abb6 rdf:first :Item ;
    rdf:rest () ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb6 .

_:nf7c16469ece44a5db0d447cd588522abb7 rdf:first :Work ;
    rdf:rest _:nf7c16469ece44a5db0d447cd588522abb8 ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb7 .

_:nf7c16469ece44a5db0d447cd588522abb8 rdf:first :Expression ;
    rdf:rest _:nf7c16469ece44a5db0d447cd588522abb9 ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb8 .

_:nf7c16469ece44a5db0d447cd588522abb9 rdf:first :Manifestation ;
    rdf:rest () ;
    owl:sameAs _:nf7c16469ece44a5db0d447cd588522abb9 .