# Dependances pre-provisionnees (owlready2) : voir SemanticWeb/requirements.txt ; imports dans les cellules suivantes.SW-7b-Python-OWL
Navigation : Index | << SW-7 C# | SW-8 SHACL >>
Ontologies OWL en Python avec OWLReady2
Ce notebook est un sidetrack optionnel qui presente l’equivalent Python des concepts OWL du notebook SW-7 (dotNetRDF). Vous y decouvrirez OWLReady2, une bibliotheque Python pour manipuler des ontologies OWL et effectuer du raisonnement.
Objectifs d’apprentissage
A la fin de ce notebook, vous saurez : 1. Créer et manipuler des ontologies OWL avec OWLReady2 2. Définir des classes, proprietes et restrictions 3. Utiliser un raisonneur (HermiT) pour deduire de nouvelles connaissances 4. Faire la correspondance entre dotNetRDF et OWLReady2
Prerequis
- SW-7-CSharp-OWL recommande (pour la comprehension conceptuelle)
- Python 3.10+
- Java requis pour le raisonneur HermiT (inclus dans OWLReady2)
Duree estimee : 30 minutes
Note : OWLReady2 inclut le raisonneur HermiT (Java) pour le raisonnement OWL 2 DL complet.
1. Installation et Imports
OWLReady2 est la bibliotheque de reference pour manipuler des ontologies OWL en Python.
Importation de la bibliotheque OWLReady2 pour la manipulation d’ontologies OWL.
try:
from owlready2 import *
import owlready2
# Limiter la memoire JVM du raisonneur pour compatibilite JVM 32-bit (defaut owlready2 = 2000 Mo)
owlready2.reasoning.JAVA_MEMORY = 1000
OWLREADY2_AVAILABLE = True
print("OWLReady2 importe.")
except ImportError:
OWLREADY2_AVAILABLE = False
print("OWLReady2 non disponible. Installez avec : pip install owlready2")OWLReady2 importe.
2. Créer une Ontologie Simple
Commencons par créer une ontologie pour une famille de personnes, avec des classes et des proprietes.
if OWLREADY2_AVAILABLE:
# Create a new ontology
onto = get_ontology("http://example.org/family.owl#")
# Define classes
with onto:
class Person(Thing):
pass
class Man(Person):
pass
class Woman(Person):
pass
# Properties - has_child is NOT Functional (can have multiple children)
class has_child(ObjectProperty):
domain = [Person]
range = [Person]
class has_parent(ObjectProperty):
domain = [Person]
range = [Person]
# Set the inverse relationship
has_child.inverse_property = has_parent
class has_name(DataProperty, FunctionalProperty):
domain = [Person]
range = [str]
class age(DataProperty, FunctionalProperty):
domain = [Person]
range = [int, float]
print("Ontologie creee avec classes :")
print(f" Person (Thing subclass)")
print(f" Man (Person subclass)")
print(f" Woman (Person subclass)")
print()
print("Proprietes :")
print(f" has_child (ObjectProperty, inverse: has_parent)")
print(f" has_name (DataProperty, string)")
print(f" age (DataProperty, integer)")
else:
print("OWLReady2 non disponible : creation d'ontologie ignoree.")Ontologie creee avec classes :
Person (Thing subclass)
Man (Person subclass)
Woman (Person subclass)
Proprietes :
has_child (ObjectProperty, inverse: has_parent)
has_name (DataProperty, string)
age (DataProperty, integer)
Interpretation : Creation d’ontologie
Syntaxe OWLReady2 : - Thing est la classe racine OWL (equivalent de owl:Thing) - ObjectProperty relie deux individus (comme owl:ObjectProperty) - DataProperty relie un individu a une valeur litterale (comme owl:DatatypeProperty) - FunctionalProperty signifie qu’une entite ne peut avoir qu’une seule valeur (max 1)
| OWLReady2 | OWL (Turtle) | dotNetRDF |
|---|---|---|
class Person(Thing) |
:Person a owl:Class ; rdfs:subClassOf owl:Thing . |
new OntologyClass("Person") |
ObjectProperty |
a owl:ObjectProperty |
new OntologyObjectProperty("has_child") |
DataProperty |
a owl:DatatypeProperty |
new OntologyDataProperty("age") |
domain = [Person] |
rdfs:domain :Person |
.Domain = personClass |
range = [Person] |
rdfs:range :Person |
.Range = personClass |
3. Créer des Individus et Assertions
Ajoutons des individus (instances) a notre ontologie.
if OWLREADY2_AVAILABLE:
# Create individuals
john = Man("John", has_name="John Smith", age=45)
mary = Woman("Mary", has_name="Mary Smith", age=42)
alice = Woman("Alice", has_name="Alice Smith", age=15)
# Define relationships
john.has_child.append(alice)
mary.has_child.append(alice)
print("Individus crees :")
print(f" {john.name} : {john.has_name}, {john.age} ans")
print(f" {mary.name} : {mary.has_name}, {mary.age} ans")
print(f" {alice.name} : {alice.has_name}, {alice.age} ans")
print()
print("Relations parent-enfant :")
print(f" {john.name} -> has_child -> {alice.name}")
print(f" {mary.name} -> has_child -> {alice.name}")
print()
print("Propriete inverse (auto-generee) :")
print(f" {alice.name} -> has_parent -> {[p.name for p in alice.has_parent]}")
else:
print("OWLReady2 non disponible : creation d'individus ignoree.")Individus crees :
John : John Smith, 45 ans
Mary : Mary Smith, 42 ans
Alice : Alice Smith, 15 ans
Relations parent-enfant :
John -> has_child -> Alice
Mary -> has_child -> Alice
Propriete inverse (auto-generee) :
Alice -> has_parent -> ['John', 'Mary']
Interpretation : Individus
OWLReady2 utilise une syntaxe Python intuitive : - Man("John", ...) créé un individu de la classe Man avec l’IRI #John - Les proprietes sont accessibles comme des attributs Python - Les proprietes inverse sont automatiquement maintenues
| Opération | OWLReady2 | OWL (Turtle) |
|---|---|---|
| Créer individu | john = Man("John") |
:John a :Man . |
| Assert propriete | john.has_child.append(alice) |
:John :has_child :Alice . |
| Propriete data | john.has_name = "John" |
:John :has_name "John" . |
4. Restrictions OWL
OWL permet d’exprimer des restrictions sur les classes. Creons une nouvelle ontologie avec des restrictions.
if OWLREADY2_AVAILABLE:
# Create a new ontology with restrictions
onto2 = get_ontology("http://example.org/company.owl#")
with onto2:
class Person(Thing):
pass
class Department(Thing):
pass
class works_in(ObjectProperty):
domain = [Person]
range = [Department]
class manages(ObjectProperty):
domain = [Person]
range = [Department]
# Restriction: Manager is someone who manages at least one department
class Manager(Person):
equivalent_to = [Person & manages.some(Department)]
# Restriction: Employee is someone who works in some department
class Employee(Person):
equivalent_to = [Person & works_in.some(Department)]
print("Classes avec restrictions :")
print(f" Manager = Person AND manages SOME Department")
print(f" Employee = Person AND works_in SOME Department")
print()
print("Restriction OWLReady2 :")
print(f" manages.some(Department) = exists manages . Department")
print(f" Person & manages.some(Department) = Person AND (exists manages . Department)")
else:
print("OWLReady2 non disponible : restrictions ignorees.")Classes avec restrictions :
Manager = Person AND manages SOME Department
Employee = Person AND works_in SOME Department
Restriction OWLReady2 :
manages.some(Department) = exists manages . Department
Person & manages.some(Department) = Person AND (exists manages . Department)
Interpretation : Restrictions OWL
| Restriction OWLReady2 | OWL (Manchester) | Turtle | Signification |
|---|---|---|---|
manages.some(Department) |
manages some Department |
owl:someValuesFrom |
∃ : au moins 1 |
manages.only(Department) |
manages only Department |
owl:allValuesFrom |
∀ : seulement |
manages.max(1) |
manages max 1 |
owl:maxCardinality |
≤ 1 |
manages.min(1) |
manages min 1 |
owl:minCardinality |
≥ 1 |
manages.exactly(1) |
manages exactly 1 |
owl:cardinality |
= 1 |
Equivalent dotNetRDF : Restrictions avec OntologyClass et expressions OWL.
5. Raisonnement avec HermiT
OWLReady2 inclut le raisonneur HermiT qui peut deduire de nouvelles connaissances a partir de l’ontologie.
if OWLREADY2_AVAILABLE:
# Create individuals and run reasoning
import subprocess
# Check if Java is available for HermiT reasoner
java_available = False
try:
result = subprocess.run(["java", "-version"], capture_output=True, text=True)
java_available = result.returncode == 0
except FileNotFoundError:
pass
with onto2:
it_dept = Department("IT")
hr_dept = Department("HR")
bob = Person("Bob")
alice = Person("Alice")
charlie = Person("Charlie")
bob.works_in = [it_dept]
alice.works_in = [hr_dept]
charlie.manages = [it_dept]
charlie.works_in = [it_dept] # Charlie also works in IT
print("=== Avant raisonnement ===")
print(f"Bob types : {bob.is_a}")
print(f"Alice types : {alice.is_a}")
print(f"Charlie types : {charlie.is_a}")
print()
if java_available:
# Run HermiT reasoner
with onto2:
sync_reasoner()
print("=== Apres raisonnement (HermiT) ===")
print(f"Bob types : {bob.is_a}")
print(f"Alice types : {alice.is_a}")
print(f"Charlie types : {charlie.is_a}")
print()
print("Deductions :")
print(f" Bob est Employee (car works_in SOME Department)")
print(f" Alice est Employee (car works_in SOME Department)")
print(f" Charlie est Employee ET Manager (car works_in ET manages)")
else:
print("=== Java non disponible - Raisonnement ignore ===")
print("Le raisonneur HermiT necessite Java pour fonctionner.")
print("Installez Java pour activer le raisonnement OWL 2 DL complet.")
print()
print("Resultats attendus apres raisonnement :")
print(" Bob -> Employee (car works_in SOME Department)")
print(" Alice -> Employee (car works_in SOME Department)")
print(" Charlie -> Employee + Manager (car works_in ET manages)")
else:
print("OWLReady2 non disponible : raisonnement ignore.")=== Avant raisonnement ===
Bob types : [company.Person]
Alice types : [company.Person]
Charlie types : [company.Person]
=== Apres raisonnement (HermiT) ===
Bob types : [company.Employee]
Alice types : [company.Employee]
Charlie types : [company.Employee, company.Manager]
Deductions :
Bob est Employee (car works_in SOME Department)
Alice est Employee (car works_in SOME Department)
Charlie est Employee ET Manager (car works_in ET manages)
Interpretation : Raisonnement
Le raisonneur HermiT a deduit : - Bob est Employee : il travaille dans un departement (IT) - Alice est Employee : elle travaille dans un departement (HR) - Charlie est Employee ET Manager : il travaille dans ET dirige un departement
| Opération | OWLReady2 | dotNetRDF |
|---|---|---|
| Raisonnement | sync_reasoner() (HermiT) |
OntologyGraph avec RdfsReasoner |
| Types inférés | .is_a (mis a jour) |
GetTypes() (inclus inférés) |
| Raisonneur | HermiT (OWL 2 DL complet) | RDFS + OWL 2 RL limite |
Note : HermiT est un raisonneur OWL 2 DL complet, beaucoup plus puissant que le raisonneur RDFS de base de dotNetRDF.
6. Charger une Ontologie Existante
OWLReady2 peut charger des ontologies depuis des fichiers ou des URLs.
if OWLREADY2_AVAILABLE:
# Load the university ontology (if available)
import os
ontology_file = "data/university.owl"
if os.path.exists(ontology_file):
# Load existing ontology
onto_univ = get_ontology("file://" + os.path.abspath(ontology_file)).load()
print(f"Ontologie chargee : {onto_univ.base_iri}")
print(f"Classes : {len(list(onto_univ.classes()))}")
print(f"Individuals : {len(list(onto_univ.individuals()))}")
print()
# Show some classes
print("Classes dans l'ontologie :")
for cls in list(onto_univ.classes())[:10]:
print(f" {cls.name}")
else:
print(f"Fichier {ontology_file} non trouve.")
print("Utilisation de l'ontologie de demonstration interne.")
# Use our demo ontology
onto_univ = onto
print(f"\nOntologie de demonstration : {onto_univ.base_iri}")
for cls in onto_univ.classes():
print(f" {cls.name}")
else:
print("OWLReady2 non disponible : chargement d'ontologie ignore.")Ontologie chargee : http://example.org/university#
Classes : 6
Individuals : 6
Classes dans l'ontologie :
Student
Course
Professor
Person
Department
GraduateStudent
7. Exporter une Ontologie
OWLReady2 peut exporter les ontologies dans différents formats.
if OWLREADY2_AVAILABLE:
# Export ontology to RDF/XML
onto2.save(file="data/temp_company.owl", format="rdfxml")
print("Ontologie exportee : data/temp_company.owl")
print()
# Also export to Turtle
onto2.save(file="data/temp_company.ttl", format="ntriples")
print("Ontologie exportee : data/temp_company.ttl")
print()
# Show first 20 lines of the Turtle export
print("=== Apercu Turtle (20 premieres lignes) ===")
with open("data/temp_company.ttl", "r") as f:
for i, line in enumerate(f):
if i >= 20:
break
print(line.rstrip())
else:
print("OWLReady2 non disponible : export ignore.")Ontologie exportee : data/temp_company.owl
Ontologie exportee : data/temp_company.ttl
=== Apercu Turtle (20 premieres lignes) ===
<http://example.org/company.owl> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Ontology> .
<http://example.org/company.owl#Person> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .
<http://example.org/company.owl#Person> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2002/07/owl#Thing> .
<http://example.org/company.owl#Department> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .
<http://example.org/company.owl#Department> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2002/07/owl#Thing> .
<http://example.org/company.owl#works_in> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
<http://example.org/company.owl#works_in> <http://www.w3.org/2000/01/rdf-schema#domain> <http://example.org/company.owl#Person> .
<http://example.org/company.owl#works_in> <http://www.w3.org/2000/01/rdf-schema#range> <http://example.org/company.owl#Department> .
<http://example.org/company.owl#manages> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#ObjectProperty> .
<http://example.org/company.owl#manages> <http://www.w3.org/2000/01/rdf-schema#domain> <http://example.org/company.owl#Person> .
<http://example.org/company.owl#manages> <http://www.w3.org/2000/01/rdf-schema#range> <http://example.org/company.owl#Department> .
<http://example.org/company.owl#Manager> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .
<http://example.org/company.owl#Manager> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://example.org/company.owl#Person> .
_:2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Restriction> .
_:2 <http://www.w3.org/2002/07/owl#onProperty> <http://example.org/company.owl#manages> .
_:2 <http://www.w3.org/2002/07/owl#someValuesFrom> <http://example.org/company.owl#Department> .
_:3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Class> .
_:3 <http://www.w3.org/2002/07/owl#intersectionOf> _:1 .
_:1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.org/company.owl#Person> .
_:1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:4 .
8. Tableau de Correspondance dotNetRDF / OWLReady2
Ce tableau recapitule les equivalences pour la manipulation d’ontologies.
| Opération | dotNetRDF (C#) | OWLReady2 (Python) |
|---|---|---|
| Créer ontologie | new OntologyGraph() |
get_ontology("uri#") |
| Créer classe | new OntologyClass("Person") |
class Person(Thing): pass |
| Sous-classe | subClassOf |
class Person(Thing): pass |
| ObjectProperty | new OntologyObjectProperty("knows") |
class knows(ObjectProperty): pass |
| DataProperty | new OntologyDataProperty("age") |
class age(DataProperty): pass |
| Créer individu | g.CreateUriNode("ex:John") + assertions |
john = Person("John") |
| Assert propriete | g.Assert(new Triple(...)) |
john.knows.append(alice) |
| Restriction SOME | new SomeValuesRestriction(...) |
knows.some(Person) |
| Restriction ONLY | new AllValuesRestriction(...) |
knows.only(Person) |
| Raisonnement | new RdfsReasoner().Apply(graph) |
sync_reasoner() (HermiT) |
| Charger fichier | FileLoader.Load(graph, file) |
get_ontology("file://...").load() |
| Exporter | new CompressingTurtleWriter().Save() |
onto.save(file="...") |
Différences philosophiques
| Aspect | dotNetRDF | OWLReady2 |
|---|---|---|
| Style | Triple-based (bas niveau) | Class-based (haut niveau) |
| Modificate | Modifications directes de triples | Python classes + instances |
| Raisonneur | RDFS + OWL RL | HermiT (OWL 2 DL complet) |
| Performance | Rapide pour gros graphes | Optimise pour ontologies |
Choix : Utilisez dotNetRDF pour des graphes RDF generiques, OWLReady2 pour des ontologies OWL avec raisonnement complexe.
Exemples guides (issus de contributions etudiantes)
Les exercices ci-dessous ont ete resolus et valides a partir de contributions etudiantes ; ils sont conserves comme exemples guides d’utilisation d’OWL et du raisonneur HermiT. De nouveaux exercices a completer sont proposes a la fin du notebook.
Exemple guide 1 : Famille avec restrictions
Ontologie de famille : - Classes : Person, Parent, Child - Propriete : has_child (inverse : has_parent) - Restrictions : Parent = Person qui has_child SOME Person ; Child = Person qui has_parent SOME Person
Résultat : après sync_reasoner, HermiT reclasse Pierre et Marie en Parent, et Lucie en Child.
if OWLREADY2_AVAILABLE:
# Exemple guide 1 : famille avec restrictions OWL
# Parent et Child sont definis par equivalent_to ; HermiT reclasse les individus
from owlready2 import World
world_family = World()
onto_family = world_family.get_ontology("http://example.org/family2.owl#")
with onto_family:
# Define classes
class Person(Thing):
pass
class has_child(ObjectProperty):
domain = [Person]
range = [Person]
class has_parent(ObjectProperty):
domain = [Person]
range = [Person]
has_child.inverse_property = has_parent
class Parent(Person):
equivalent_to = [Person & has_child.some(Person)]
class Child(Person):
equivalent_to = [Person & has_parent.some(Person)]
# Create individuals and test reasoning
pierre = Person("Pierre")
marie = Person("Marie")
lucie = Person("Lucie")
pierre.has_child.append(lucie)
marie.has_child.append(lucie)
print("=== Avant raisonnement ===")
print(f"Pierre : {[c.name for c in pierre.is_a]}")
print(f"Marie : {[c.name for c in marie.is_a]}")
print(f"Lucie : {[c.name for c in lucie.is_a]}")
with onto_family:
sync_reasoner(world_family, infer_property_values=True)
print()
print("=== Apres raisonnement ===")
print(f"Pierre : {[c.name for c in pierre.is_a]}")
print(f"Marie : {[c.name for c in marie.is_a]}")
print(f"Lucie : {[c.name for c in lucie.is_a]}")
else:
print("OWLReady2 non disponible : exemple guide 1 ignore.")=== Avant raisonnement ===
Pierre : ['Person']
Marie : ['Person']
Lucie : ['Person']
=== Apres raisonnement ===
Pierre : ['Parent']
Marie : ['Parent']
Lucie : ['Child']
Exemple guide 2 : Graphe de connaissances de films
Ontologie de films : - Classes : Movie, Person (acteur/realisateur), Genre - Proprietes : has_actor, has_director, has_genre - Restriction : ActionMovie = Movie qui has_genre SOME Action
Résultat : après raisonnement, DarkKnight est classe ActionMovie.
if OWLREADY2_AVAILABLE:
# Exemple guide 2 : ontologie de films
# ActionMovie = Movie & has_genre.some(Action) ; HermiT classe DarkKnight
world_movies = World()
onto_movies = world_movies.get_ontology("http://example.org/movies.owl#")
with onto_movies:
class Movie(Thing):
pass
class Person(Thing):
pass
class Genre(Thing):
pass
class has_actor(ObjectProperty):
domain = [Movie]
range = [Person]
class has_director(ObjectProperty):
domain = [Movie]
range = [Person]
class has_genre(ObjectProperty):
domain = [Movie]
range = [Genre]
class Action(Genre):
pass
class Drama(Genre):
pass
class ActionMovie(Movie):
equivalent_to = [Movie & has_genre.some(Action)]
action = Action("ActionGenre")
drama = Drama("DramaGenre")
nolan = Person("Nolan")
bale = Person("Bale")
hardy = Person("Hardy")
dark_knight = Movie("DarkKnight")
dark_knight.has_director.append(nolan)
dark_knight.has_actor.append(bale)
dark_knight.has_actor.append(hardy)
dark_knight.has_genre.append(action)
interstellar = Movie("Interstellar")
interstellar.has_director.append(nolan)
interstellar.has_genre.append(drama)
print("=== Avant raisonnement ===")
print(f"DarkKnight : {[c.name for c in dark_knight.is_a]}")
print(f"Interstellar : {[c.name for c in interstellar.is_a]}")
with onto_movies:
sync_reasoner(world_movies)
print()
print("=== Apres raisonnement ===")
print(f"DarkKnight : {[c.name for c in dark_knight.is_a]}")
print(f"Interstellar : {[c.name for c in interstellar.is_a]}")
else:
print("OWLReady2 non disponible : exemple guide 2 ignore.")=== Avant raisonnement ===
DarkKnight : ['Movie']
Interstellar : ['Movie']
=== Apres raisonnement ===
DarkKnight : ['ActionMovie']
Interstellar : ['Movie']
Resume et perspectives
Ce sidetrack a presente la manipulation d’ontologies OWL en Python avec OWLReady2, en mettant en lumiere la différence de philosophie avec dotNetRDF. Alors que dotNetRDF travaille au niveau des triples (bas niveau), OWLReady2 offre une API orientee classes (haut niveau) ou les ontologies sont définies comme des classes Python heritant de Thing, les proprietes comme des sous-classes d’ObjectProperty ou DataProperty, et les restrictions OWL s’expriment naturellement (manages.some(Department) pour someValuesFrom).
Le point fort d’OWLReady2 est l’integration du raisonneur HermiT (OWL 2 DL complet), qui permet de deduire automatiquement de nouvelles connaissances. Les exemples guides ont illustre cette puissance : classification automatique d’individus en Employee ou Manager selon leurs proprietes, classification en Parent/Child via les restrictions equivalent_to, et même la categorisation de films en ActionMovie selon leur genre. L’exemple de synthese sur les ecosystemes a combine hiérarchie de classes, restrictions et raisonnement pour classifier le renard et le loup comme carnivores.
Dans le notebook suivant (SW-8-Python-SHACL), nous aborderons la validation de données avec pySHACL, puis SW-9-Python-JSONLD presentera le format JSON-LD pour l’integration web, avant le notebook SW-11-Python-KnowledgeGraphs qui combine ces technologies pour construire des graphes de connaissances.
Concepts cles
| Concept | Ce que vous avez appris |
|---|---|
| OWLReady2 | Manipuler des ontologies OWL en Python |
| Classes/Proprietes | Définir la structure d’une ontologie |
| Restrictions | some (someValuesFrom), all (allValuesFrom), cardinalites |
| HermiT | Raisonneur OWL 2 DL complet |
| Correspondance | Equivalences dotNetRDF / OWLReady2 |
Prochaines étapes
- SW-8-Python-SHACL : Validation de données avec pySHACL
- SW-9-Python-JSONLD : Données structurees pour le web
- SW-11-Python-KnowledgeGraphs : Graphes de connaissances avec kglab
Retour au sommaire : Index SemanticWeb
Exemple guide de synthese : Ontologie avec raisonnement
Ontologie d’ecosysteme construite avec owlready2, raisonnee avec HermiT.
- 3 classes avec hiérarchie :
Animal,Mammifere,Carnivore - 1 restriction :
Carnivore= Animal quihas_preySOME Animal - Instances dont le type est derive par inference (Renard, Loup -> Carnivore)
if OWLREADY2_AVAILABLE:
# Exemple guide de synthese : ontologie d'ecosystemes avec raisonnement
# Carnivore = Animal & has_prey.some(Animal) ; HermiT classe Renard et Loup
from owlready2 import get_ontology, Thing, ObjectProperty, sync_reasoner, World
# Etape 1 : creer l'ontologie avec get_ontology
world_eco = World()
onto_eco = world_eco.get_ontology("http://example.org/ecosystem.owl#")
# Etape 2 : definir les classes et proprietes (Animal, Mammifere, Carnivore, has_prey)
with onto_eco:
class Animal(Thing):
pass
class Mammifere(Animal):
pass
class has_prey(ObjectProperty):
domain = [Animal]
range = [Animal]
class Carnivore(Animal):
equivalent_to = [Animal & has_prey.some(Animal)]
# Etape 3 : ajouter des instances
lapin = Mammifere("Lapin")
souris = Mammifere("Souris")
renard = Mammifere("Renard")
loup = Mammifere("Loup")
renard.has_prey.append(lapin)
loup.has_prey.append(souris)
loup.has_prey.append(lapin)
print("=== Avant raisonnement ===")
for ind in [lapin, souris, renard, loup]:
print(f" {ind.name} : {[c.name for c in ind.is_a]}")
# Etape 4 : lancer le raisonneur sync_reasoner_pellet et afficher les types inferes
with onto_eco:
sync_reasoner(world_eco)
print()
print("=== Apres raisonnement ===")
for ind in [lapin, souris, renard, loup]:
print(f" {ind.name} : {[c.name for c in ind.is_a]}")
# Etape 5 (bonus) : exporter l'ontologie
onto_eco.save(file="data/temp_ecosystem.owl", format="rdfxml")
print()
print("Ontologie exportee : data/temp_ecosystem.owl")
else:
print("OWLReady2 non disponible : exemple de synthese ignore.")=== Avant raisonnement ===
Lapin : ['Mammifere']
Souris : ['Mammifere']
Renard : ['Mammifere']
Loup : ['Mammifere']
=== Apres raisonnement ===
Lapin : ['Mammifere']
Souris : ['Mammifere']
Renard : ['Mammifere', 'Carnivore']
Loup : ['Mammifere', 'Carnivore']
Ontologie exportee : data/temp_ecosystem.owl
Exemple guide 3 : Ontologie de LLM
Ontologie de modèles d’intelligence artificielle : - Classes : AIModel, LLM, Organization, Benchmark, Capability (avec sous-classes ImageUnderstanding, CodeGeneration, Reasoning) - Proprietes : developed_by, has_capability, evaluated_on, outperforms - Restrictions : MultimodalLLM = LLM qui has_capability SOME ImageUnderstanding ; CodingLLM = LLM qui has_capability SOME CodeGeneration ; ReasoningLLM = LLM qui has_capability SOME Reasoning
Résultat : après raisonnement, HermiT classe Claude comme ReasoningLLM + CodingLLM + MultimodalLLM, GPT4 comme CodingLLM + MultimodalLLM, Gemini comme ReasoningLLM + MultimodalLLM, et Llama comme CodingLLM.
Contribue par louisparmentiermichelet-hue (PR #1932, cohorte 2026)
if OWLREADY2_AVAILABLE:
# Exemple guide 3 : ontologie de LLM avec raisonnement
# Contribue par louisparmentiermichelet-hue (PR #1932, cohorte 2026)
# MultimodalLLM / CodingLLM / ReasoningLLM definis par equivalent_to ; HermiT classe les modeles
from owlready2 import World
llm_world = World()
onto_llm = llm_world.get_ontology("http://example.org/llm.owl#")
with onto_llm:
# Classes de base
class AIModel(Thing):
pass
class LLM(AIModel):
pass
class Organization(Thing):
pass
class Benchmark(Thing):
pass
class Capability(Thing):
pass
# Proprietes
class developed_by(ObjectProperty):
pass
class has_capability(ObjectProperty):
pass
class evaluated_on(ObjectProperty):
pass
class outperforms(ObjectProperty):
pass
# Sous-classes de Capability
class ImageUnderstanding(Capability):
pass
class CodeGeneration(Capability):
pass
class Reasoning(Capability):
pass
# Classes definies par restrictions equivalent_to
class MultimodalLLM(LLM):
equivalent_to = [LLM & has_capability.some(ImageUnderstanding)]
class CodingLLM(LLM):
equivalent_to = [LLM & has_capability.some(CodeGeneration)]
class ReasoningLLM(LLM):
equivalent_to = [LLM & has_capability.some(Reasoning)]
# Individus
with onto_llm:
org_anthropic = Organization("Anthropic")
org_openai = Organization("OpenAI")
org_google = Organization("Google")
org_meta = Organization("Meta")
cap_image = ImageUnderstanding("cap_image")
cap_code = CodeGeneration("cap_code")
cap_reason = Reasoning("cap_reason")
bench_mmlu = Benchmark("MMLU")
bench_humaneval = Benchmark("HumanEval")
claude = LLM("Claude")
claude.developed_by = [org_anthropic]
claude.has_capability = [cap_image, cap_code, cap_reason]
claude.evaluated_on = [bench_mmlu]
gpt4 = LLM("GPT4")
gpt4.developed_by = [org_openai]
gpt4.has_capability = [cap_image, cap_code]
gpt4.evaluated_on = [bench_mmlu, bench_humaneval]
gemini = LLM("Gemini")
gemini.developed_by = [org_google]
gemini.has_capability = [cap_image, cap_reason]
llama = LLM("Llama")
llama.developed_by = [org_meta]
llama.has_capability = [cap_code]
AllDifferent([claude, gpt4, gemini, llama,
org_anthropic, org_openai, org_google, org_meta,
cap_image, cap_code, cap_reason,
bench_mmlu, bench_humaneval])
print("=== Avant raisonnement ===")
for m in [claude, gpt4, gemini, llama]:
print(f" {m.name:10} types : {[c.name for c in m.is_a]}")
print()
with onto_llm:
sync_reasoner(llm_world, infer_property_values=True)
print("=== Apres raisonnement (HermiT) ===")
for m in [claude, gpt4, gemini, llama]:
print(f" {m.name:10} types : {[c.name for c in m.is_a]}")
print(f" Organisation : {[o.name for o in m.developed_by]}")
onto_llm.save(file="data/temp_llm_ontology.owl", format="rdfxml")
print()
print("Ontologie exportee : data/temp_llm_ontology.owl")
else:
print("OWLReady2 non disponible : exemple guide 3 ignore.")=== Avant raisonnement ===
Claude types : ['LLM']
GPT4 types : ['LLM']
Gemini types : ['LLM']
Llama types : ['LLM']
=== Apres raisonnement (HermiT) ===
Claude types : ['ReasoningLLM', 'CodingLLM', 'MultimodalLLM']
Organisation : ['Anthropic']
GPT4 types : ['CodingLLM', 'MultimodalLLM']
Organisation : ['OpenAI']
Gemini types : ['ReasoningLLM', 'MultimodalLLM']
Organisation : ['Google']
Llama types : ['CodingLLM']
Organisation : ['Meta']
Ontologie exportee : data/temp_llm_ontology.owl
Exercice 1 : Vehicules electriques (equivalent_to + raisonnement)
Construisez une ontologie de vehicules : - Classes : Vehicle, Battery, ElectricVehicle - Propriete : has_battery - Restriction : ElectricVehicle = Vehicle qui has_battery SOME Battery
Créez un vehicule muni d’une batterie, lancez le raisonneur et verifiez qu’il est classe ElectricVehicle.
Indice : sur le modèle de l’exemple guide 1, utilisez equivalent_to = [Vehicle & has_battery.some(Battery)] puis sync_reasoner.
# Exercice 1 : vehicules electriques (equivalent_to + raisonnement)
# TODO etudiant : definir Vehicle, Battery, ElectricVehicle = Vehicle & has_battery.some(Battery)
# Indice : creer un World(), une ontologie, puis sync_reasoner et verifier is_a
print("Exercice a completer")Exercice a completer
Exercice 2 : Classes disjointes
Dans une ontologie d’animaux, declarez que Herbivore et Carnivore sont disjointes (AllDisjoint). Créez un individu, puis observez le comportement du raisonneur (il ne doit pas inferer qu’un même individu est a la fois Herbivore et Carnivore).
Indice : utilisez AllDisjoint([Herbivore, Carnivore]) a l’interieur du bloc with onto:.
# Exercice 2 : classes disjointes (AllDisjoint)
# TODO etudiant : declarer Herbivore et Carnivore disjointes via AllDisjoint([...])
# Indice : a placer dans le bloc with onto: , puis creer un individu et raisonner
print("Exercice a completer")Exercice a completer
Exercice 3 : Restrictions de cardinalite (min, exactly)
Modelisez la classe BigFamily = Person qui has_child au moins 3 Person. Créez ensuite la classe Couple = Person qui has_partner exactement 1 Person.
Créez un individu avec 3+ enfants, lancez le raisonneur et verifiez qu’il est classe BigFamily.
Indice : equivalent_to = [Person & has_child.min(3, Person)] pour le minimum. Utilisez .exactly(N, Class) pour la cardinalite exacte.
# Exercice 3 : restrictions de cardinalite (min, exactly)
# TODO etudiant : definir BigFamily = Person & has_child.min(3, Person)
# Indice : creer un parent avec 3 enfants ; sync_reasoner ; verifier is_a BigFamily
print("Exercice a completer")Exercice a completer
Exercice 4 : Restriction universelle only (AllValuesFrom)
Modelisez la classe Vegan = Person qui eats uniquement des Plant. Attention : some (existentiel) signifie ‘au moins un’, tandis que only (universel) signifie ‘tous’. Un Vegan n’est PAS forcement défini par ‘mange au moins une plante’ mais par ‘tout ce qu’il mange est une plante’.
Créez deux individus : Alice qui mange uniquement des plantes (Carrot, Apple), et Bob qui mange une plante et un animal (Carrot, Cow). Après raisonnement, seul Alice doit etre classe Vegan.
Indice : equivalent_to = [Person & eats.only(Plant)]. Definissez Plant et Animal comme classes disjointes (AllDisjoint).
# Exercice 4 : restriction universelle only (AllValuesFrom)
# TODO etudiant : Vegan = Person & eats.only(Plant)
# Indice : 2 individus (Alice tout-plantes, Bob plante+animal) ; seul Alice doit etre Vegan
print("Exercice a completer")Exercice a completer
Exercice 5 : Propriete transitive (TransitiveProperty)
Modelisez la propriete is_part_of comme transitive : si A is_part_of B et B is_part_of C, alors le raisonneur doit inferer A is_part_of C.
Créez les individus Finger, Hand, Arm, Body avec la chaîne : - Finger is_part_of Hand - Hand is_part_of Arm - Arm is_part_of Body
Après sync_reasoner, verifiez que Finger.is_part_of contient bien Body (via transitivite).
Indice : declarer la classe is_part_of(ObjectProperty, TransitiveProperty).
# Exercice 5 : propriete transitive
# TODO etudiant : declarer is_part_of(ObjectProperty, TransitiveProperty)
# Indice : chaine Finger -> Hand -> Arm -> Body ; sync_reasoner ; verifier Finger.is_part_of inclut Body
print("Exercice a completer")Exercice a completer
Exercices
A votre tour. Completez les exercices ci-dessous (les solutions ne sont pas fournies). Le notebook doit pouvoir s’executer de bout en bout même si les exercices ne sont pas encore completes.
Exercice 6 : Ontologie de domaine libre
Choisissez un domaine de votre choix (musique, sport, cuisine, etc.) et créez une ontologie OWL complete :
- Au moins 5 classes avec une hiérarchie coherente
- Au moins 3 proprietes (ObjectProperty ou DataProperty)
- Des restrictions
equivalent_topour définir des classes par leur comportement - Des individus pour tester le raisonnement
- Utilisez
sync_reasoner()pour verifier les inferences
Indice : inspirez-vous des exemples guides 1-3. Definissez vos classes avec equivalent_to = [ClasseParent & propriete.some(ClasseCible)], créez des individus, puis lancez sync_reasoner pour observer les classifications automatiques.
# Exercice 6 : Ontologie de domaine libre
# TODO etudiant : Choisissez un domaine (musique, sport, cuisine, etc.)
# et creez une ontologie OWL avec au moins 5 classes, 3 proprietes,
# des restrictions equivalent_to, et des individus.
# Utilisez sync_reasoner() pour verifier les inferences.
result = None # TODO etudiant : remplacer par votre ontologie
print("Exercice a completer : ontologie de domaine libre")Exercice a completer : ontologie de domaine libre
Conclusion
Ce sidetrack a presente la manipulation d’ontologies OWL en Python avec OWLReady2, en mettant en lumiere son approche orientee classes (haut niveau) par rapport a l’approche triple-based de dotNetRDF. Vous avez appris a définir des classes, proprietes et restrictions OWL directement en syntaxe Python, a créer des individus et assertions, et a exploiter le raisonneur HermiT pour deduire automatiquement de nouvelles connaissances (classification en Employee/Manager, Parent/Child, Carnivore).
Les points cles a retenir sont la puissance du raisonnement OWL 2 DL via sync_reasoner() qui reclassifie les individus selon leurs proprietes, les restrictions equivalent_to avec .some() et .only() pour définir des classes par leur comportement, et l’export multi-format (RDF/XML, Turtle) pour l’integration dans d’autres outils. Ces competences preparent a la validation de données avec SHACL et a la construction de graphes de connaissances.