Milch (DE)#

Die maßgebliche Motivation für GenDifS ist das Konzept der skos:Collection-Klasse, veranschaulicht in dem Milch-Beispiel aus dem SKOS-Primer 4 Advanced SKOS: When KOSs are not Simple Anymore > 4.1 Collections of Concepts:

milk
  <milk by source animal>
    cow milk
    goat milk
    buffalo milk

In GenDifS wird diese Differenzierung wir folgt modelliert:

from gd05 import GenDifS_Map
mm = "Milch_DE"
o = GenDifS_Map(f"../mm/{mm}.mm")
cwd into input_dir: /home/dsci/a/l/LA_2022_ws/mm
reading /home/dsci/a/l/LA_2022_ws/mm > Milch_DE.mm (6 nodes)
Parsing XML: #1 start nodes
ontology node IDs: {'ID_1896225313': 'ONTOLOGY'}
RDF: 74 388
warning: no glossary file found.
updated mindmap with backup to /home/dsci/a/l/LA_2022_ws/mm/Milch_DE.mm_backup_2022-11-20T13-50-07
o.rdflib.serialize(destination=f"../ttl/{mm}.ttl")
o.parser_markdown()
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/miniconda3/lib/python3.9/shutil.py:825, in move(src, dst, copy_function)
    824 try:
--> 825     os.rename(src, real_dst)
    826 except OSError:

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpvymps1gh' -> '../ttl/Milch_DE.ttl'

During handling of the above exception, another exception occurred:

FileNotFoundError                         Traceback (most recent call last)
Cell In [2], line 1
----> 1 o.rdflib.serialize(destination=f"../ttl/{mm}.ttl")
      2 o.parser_markdown()

File ~/miniconda3/lib/python3.9/site-packages/rdflib/graph.py:1210, in Graph.serialize(self, destination, format, base, encoding, **args)
   1208 dest = url2pathname(path) if scheme == "file" else location
   1209 if hasattr(shutil, "move"):
-> 1210     shutil.move(name, dest)
   1211 else:
   1212     shutil.copy(name, dest)

File ~/miniconda3/lib/python3.9/shutil.py:845, in move(src, dst, copy_function)
    843         rmtree(src)
    844     else:
--> 845         copy_function(src, real_dst)
    846         os.unlink(src)
    847 return real_dst

File ~/miniconda3/lib/python3.9/shutil.py:444, in copy2(src, dst, follow_symlinks)
    442 if os.path.isdir(dst):
    443     dst = os.path.join(dst, os.path.basename(src))
--> 444 copyfile(src, dst, follow_symlinks=follow_symlinks)
    445 copystat(src, dst, follow_symlinks=follow_symlinks)
    446 return dst

File ~/miniconda3/lib/python3.9/shutil.py:266, in copyfile(src, dst, follow_symlinks)
    264 with open(src, 'rb') as fsrc:
    265     try:
--> 266         with open(dst, 'wb') as fdst:
    267             # macOS
    268             if _HAS_FCOPYFILE:
    269                 try:

FileNotFoundError: [Errno 2] No such file or directory: '../ttl/Milch_DE.ttl'

Anschauliche Erklärung: Offensichtlich sind in diesem Beispiel zwei parallele Teilmengen-Beziehungen enthalten. Die erste, in Fettdruck wiedergegebene Beziehung besteht zwischen den Hauptklassen Milch und Kuhmilch und spannt insgesamt den für Mindmaps typischen Primärbaum auf:

:Kuhmilch rdfs:subClassOf :Milch

Mit diesem Baum ist aber auch eine zweite, in der Abbildung in unterstrichenem Kursivdruck wiedergegebene Beziehung zwischen charakterisierenden Sekundärbaum eng verflochten:

:Kuh rdfs:subClassOf :Tier

In GenDifS werden zwei wie hier zusammengehörenden Bäume ineinander verflochten modelliert. Dieses Syntax-Detail von GenDifS entspringt der Beobachtung, dass wir oft einen Sekundärbaum verwenden, um einen Primärbaum zu modellieren.

In Protegé sieht man, dass hier (mindestens) die folgenden zwei Begriffsbäume enthalten sind:

Milch > BY Fleisch_hat_Herkunft SOME Tier >> Kuhmilch >>> SOME Kuh

Fig. 1 Beispiel Milch in Protegé#

T-Box: OWL-Klassen und -Inferencing#

Wir betrachten den Satz:

Kuhmilch ist eine Milch, die von Rindern kommt.

In diesem Satz sind diese Informationen enthalten:

  • Kuhmilch: Darum geht es im folgenden; Subjekt

  • ist: die Beziehung zum Oberbegriff ist (hier) eine Teilmengenbeziehung

  • eine Milch ...: erste Chrakterisierung von Kuhmilch, hier durch Kennzeichnung als Teilmenge des Oberbegriffs Milch

  • eine Milch, die ...: Charakterisierung einer speziellen Teilklasse von Milch durch eine zusätzliche chrakterisierende Eigenschaft

  • von ... kommt.: chrakteristisches Attribut ist die Herkunft (und nicht z.B. der Fettgehalt)

  • ... Rindern ...: der Wert des chrakteristischen Attributs Herkunft sind Rinder.

An der Formalisierung beteiligte Mengen:

Menge 1: alle Dinge, die eine Milch sind

:Milch a owl:Class .

Menge 2: alle Dinge, die als Herkunft “Kuh” haben

:hat_Herkunft_SOME_:Kuh
  a owl:Class ;
  owl:equivalentClass [
    a owl:Restriction ;
    owl:onProperty :hat_Herkunft ;
    owl:someValuesFrom :Kuh ] .

Menge 3: alle Dinge, die eine Kuhmilch sind

:Kuhmilch a owl:Class .

Die Mengen 1-3 stehen bis jetzt völlig nebeneinander. Um Inferencing zu ermöglichen, beschreiben wir ihren Zusammenhang mit Axiomen.

Aufwärts-Inferencing#

Um ein relativ triviales Inferencing zu ermöglichen, fügen wir ein Subklassen-Axiom hinzu:

Menge 3 ist eine Teilmenge von Menge 1

:Kuhmilch rdfs:subClassOf :Milch .

Aufgrund dieser Aussage wird ein Reasoner dann, wenn ein Ding X Element der Menge 3: Kuhmilch ist, dieses Ding auch als Element der Menge 1: Milch klassifizieren.

Weil hier von einer Teilmenge auf die übergeordnete Menge geschlossen wird, wollen wir dieses Inferencing “aufwärts” nennen.

Abwärts-Inferencing#

Um ein Ding anhand seiner Eigenschaften genauer klassifizieren zu können, benötigen wir erstens eine weitere Menge:

Menge 4 = Schnittmenge von Menge 1 und Menge 2: Alle Dinge, die eine Milch sind, UND die als Herkunft Kuh haben.

:Milch_AND_:hat_Herkunft_SOME_:Kuh
  a owl:Class ;
  owl:equivalentClass [
    a owl:Class ;
    owl:intersectionOf (
      :Milch
      :hat_Herkunft_SOME_:Kuh ) ] .

Und um das Inferencing letztlich möglich zu machen, fügen wir zweitens noch eine weiteres Axiom hinzu, mit dem Menge 4 als Teilmenge von Menge 3 definiert wird:

Alle Dinge, die aus Menge 4 sind, sind automatisch auch enthalten in Menge 3

:Milch_AND_:hat_Herkunft_SOME_:Kuh
  rdfs:subClassOf :Kuhmilch .

Indem wir die Schnittmenge von Menge 1 und 2 als Teilmenge von Menge 3 definieren, wird jetzt das gesuchte Inferencing unterstützt, das uns die Klassifiation erlaubt: Gegeben sei ein Ding X, von dem wir wissen,

  • dass es eine Milch ist: X ist Element von Menge 1;

  • dass es von einer Kuh stammt: X ist gleichzeitig auch Element von Menge 2.

Aufgrund dieser Angaben wird der Reasoner X auch als Element der Menge 4 klassifizieren. Und da Menge 4 als eine Teilmenge von Menge 3 definiert wurde, wird der Reasoner dann X ebenfalls als Element der Menge 3 klassifizieren: Damit wäre der Klassifikationsschritt Milch + Herkunft Kuh = Kuhmilch durchgeführt!

Formalisierung des Abwärts-Inferencings in Mengenschreibweise:

Kuhmilch ⊇ {x | Milch(x) ∧ ∃y[hat_Herkunft(x,y) ∧ Kuh(y)] }

Formalisierung in First Order Logic (FOL):

∀x[Kuhmilch(x) ← Milch(x) ∧ ∃y[hat_Herkunft(x,y) ∧ Kuh(y)]

Formalisierung in Description Logic (DL):

Kuhmilch ⊇ X
X == Milch ∧ ∃ hat_Herkunft.Kuh

(Wir haben hier X als Abkürzung für :Milch_AND_:hat_Herkunft_SOME_:Kuh verwendet.)

A-Box#

In GenDifS wird eine Ontologie abstrakt in einer Mindmap-basierten Sprache dargestellt. Deshalb ist es nötig, die Mindmap in mindestens eine, und möglich, die Mindmap in mehr als eine Ontologiesprache zu übesetzen.

Tatsächlich übersetzen wir einen einzigen Knoten in 3 verschiedene Objekte, die wir per Namespace unterscheiden:

@prefix ex: <http://mm2ttl.net/namespace/ex#> .
@prefix x: <http://mm2ttl.net/namespace/x#> .  
@prefix : <http://mm2ttl.net/namespace/default#> .

Für Kuhmilch als OWL-Klasse verwenden wir den Namespace :. In ttl wird das Objekt :Kuhmilch also expandiert zu http://mm2ttl.net/namespace/default#Kuhmilch.

# BY/child.1, owl
:Kuhmilch    # Abkürzung für http://mm2ttl.net/namespace/default#Kuhmilch
   a owl:Class ;
   rdfs:subClassOf :milch .

Für jede OWL-Klasse legen wir eine Test-Instanz an, im Beispiel :Kuhmilch das Onjekt ex::Kuhmilch. Da das Präfix ex: zu `` expandiert wird, lautet die URI der Test-Instanz also http://mm2ttl.net/namespace/ex#:Kuhmilch. (Der verbleibende Doppelpunkt sieht vielleicht etwas komisch aus, ist aber in einer IRI syntaktisch erlaubt).

# BY/child.4, owl-test
ex::Kuhmilch  a :Kuhmilch .

ACHTUNG: Protege untedrückt in der Anzeige das Präfix. In der Folge werden http://mm2ttl.net/namespace/default#Kuhmilch und http://mm2ttl.net/namespace/ex#:Kuhmilch optisch gleich dargestellt; erst ein hover zeigt die unterschiedlichen Präfixe.

A-Box Inferencing-Test#

Um zu prüfen, ob die Übersetzung von GenDifS nach OWL korrekt erfolgt und in Kombination mit dem vorgesehenen Reasoner - hier dem OWL-RL-Reasoner owlrl - funktioniert, fügen wir den automatisch angelegten Beispiel-Instanzen zusätzliche Features hinzu. Beispiel:

<http://mm2ttl.net/namespace/ex#TEST_:Milch_6509c46dd8374fd8bf2aa5ed1d5f87ee> a :Milch ;
    gendifs:classifyLike <http://mm2ttl.net/namespace/ex#:Kuhmilch> ;
    :hat_Herkunft <http://mm2ttl.net/namespace/ex#:Kuh> .

Nach dem Inferencing durch owlrl sind für die Beispiel-Instanz <http://mm2ttl.net/namespace/ex#TEST_:Milch_6509c46dd8374fd8bf2aa5ed1d5f87ee> u.a. die folgenden Tripel in der ausmaterialisierten ttl-Datei enthalten:

<http://mm2ttl.net/namespace/ex#TEST_:Milch_6509c46dd8374fd8bf2aa5ed1d5f87ee> a
        :Kuhmilch,
        :Milch,
        <http://mm2ttl.net/namespace/default#Milch_AND_:hat_Herkunft_SOME_:Kuh>,
        <http://mm2ttl.net/namespace/default#hat_Herkunft_SOME_:Kuh>,
        owl:Thing ;
    gendifs:classifyLike <http://mm2ttl.net/namespace/ex#:Kuhmilch> ;
    :hat_Herkunft <http://mm2ttl.net/namespace/ex#:Kuh> .

SKOS#

Außerdem interpretieren wir die Mindmap als SKOS-Baum. Zum Knoten Kuhmilch erzeugen wir ein Objekt x::Kuhmilch, das zu http://mm2ttl.net/namespace/x#:Kuhmilch expandiert wird.

# BY/child.2, skos
x::Kuhmilch
   rdf:type skos:Concept ;
   rdfs:broaderTransitive x::Milch .

Alle drei Objekte habe also völlig unterschiedliche IRIS, bezeichnen völlig unterschiedliche Dinge, und können in der selben ttl-Datei (und damit auch im selben named graph) nebeneinaner auftreten und in Beziehung treten, ohne dass man mit Punning etc. arbeiten muss.