diff --git a/MyIA.AI.Notebooks/SymbolicAI/SemanticWeb/SW-3-CSharp-GraphOperations.ipynb b/MyIA.AI.Notebooks/SymbolicAI/SemanticWeb/SW-3-CSharp-GraphOperations.ipynb index d9b84f34b0..b676692947 100644 --- a/MyIA.AI.Notebooks/SymbolicAI/SemanticWeb/SW-3-CSharp-GraphOperations.ipynb +++ b/MyIA.AI.Notebooks/SymbolicAI/SemanticWeb/SW-3-CSharp-GraphOperations.ipynb @@ -13,7 +13,32 @@ }, "tags": [] }, - "source": "# SW-3-GraphOperations\n\n**Navigation** : [<< 2-RDFBasics](SW-2-CSharp-RDFBasics.ipynb) | [Index](README.md) | [4-SPARQL >>](SW-4-CSharp-SPARQL.ipynb)\n\n## Opérations sur les graphes RDF\n\n> Ce notebook manipule des **graphes RDF** au moyen de la bibliotheque **dotNetRDF** (open-source, `dotnetrdf.org`), qui implémente le modèle de données abstrait de **RDF 1.1** (Cyganiak, Wood, Lanthaler (eds.), *RDF 1.1 Concepts and Abstract Syntax*, Recommandation W3C, 25 février 2014). Les formats de sérialisation couverts (Turtle, RDF/XML, N-Triples, Notation 3, JSON-LD, TriG, N-Quads) sont tous des sérialisations normalisées de ce modèle abstrait.\n\n### Duree estimee : 50 minutes\n\nA la fin de ce notebook, vous saurez :\n1. **Lire** des fichiers RDF dans différents formats (Turtle, RDF/XML, NTriples)\n2. **Ecrire** des graphes RDF vers des fichiers et des chaînes\n3. **Fusionner** des graphes RDF avec gestion des conflits\n4. **Sélectionner** des triplets selon différents critères et avec LINQ\n5. **Manipuler** des listes RDF (créer, lire, modifier, supprimer)\n\n### Prerequis\n- .NET 9.0 avec .NET Interactive\n- Avoir complete [SW-2-RDFBasics](SW-2-CSharp-RDFBasics.ipynb)" + "source": [ + "# SW-3-GraphOperations\n", + "\n", + "**Navigation** : [<< 2-RDFBasics](SW-2-CSharp-RDFBasics.ipynb) | [Index](README.md) | [4-SPARQL >>](SW-4-CSharp-SPARQL.ipynb)\n", + "\n", + "Notebook C# / .NET Interactive sur les **opérations de graphe** dans dotNetRDF : lecture, écriture, fusion, sélection, listes RDF.\n", + "\n", + "**Objectifs de la séance** :\n", + "1. Lire des fichiers RDF dans plusieurs formats (Turtle, NTriples, RDF/XML) avec `VDS.RDF.Parsing`.\n", + "2. Sérialiser des graphes dans tous les formats standards via `VDS.RDF.Writing`.\n", + "3. Fusionner deux graphes en respectant la sémantique (pas de duplication de triplets).\n", + "4. Sélectionner des triplets par prédicat, sujet, objet -- avec LINQ pour les requêtes complexes.\n", + "5. Manipuler les listes RDF (structure chaînées, `AssertList`, `RetractList`, `AddToList`, `RemoveFromList`).\n", + "\n", + "**Pourquoi ce notebook dans la série SemanticWeb** :\n", + "- C'est l'un des notebooks techniques de la série (C# / .NET Interactive + dotNetRDF 3.2.1).\n", + "- Il illustre les opérations fondamentales sur les graphes RDF (lecture/écriture/fusion/sélection/listes).\n", + "- C'est un cas Prong B applicable (sota-not-workaround) : on utilise la vraie bibliothèque dotNetRDF (lib C# de référence pour RDF), pas une reimplementation jouet.\n", + "\n", + "**Substance pédagogique** : les graphes RDF sont le coeur du Web sémantique (W3C). La manipulation (lecture/écriture/sélection) est la base de tout traitement ulterieur (SPARQL, OWL, inférence).\n", + "\n", + "### Prerequis\n", + "- .NET 9.0 avec .NET Interactive\n", + "- Avoir complété [SW-2-RDFBasics](SW-2-CSharp-RDFBasics.ipynb)\n", + "" + ] }, { "cell_type": "code", @@ -73,7 +98,12 @@ "tags": [] }, "source": [ - "Importation des espaces de noms dotNetRDF et configuration de l'environnement de travail." + "Importation des espaces de noms dotNetRDF et configuration de l'environnement de travail. Les 3 namespaces principaux sont :\n", + "- `VDS.RDF` : classes de base (Graph, Triple, INode, IUriNode, ILiteralNode, IBlankNode).\n", + "- `VDS.RDF.Parsing` : parsers (Turtle, NTriples, RDF/XML, JSON-LD).\n", + "- `VDS.RDF.Writing` : writers (les mêmes formats, en sortie).\n", + "\n", + "**Sortie observée de code[1]** (verbatim) : `dotNetRDF 3.2.1 pret.`. La cellule exécute les `using` statements et confirme que la bibliothèque est chargée. Note : `using` en C# est équivalent à `import` en Python -- il déclare les espaces de noms accessibles sans fully-qualifier les classes." ] }, { @@ -127,6 +157,29 @@ "Console.WriteLine(\"dotNetRDF 3.2.1 pret.\");" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lecture de l'environnement dotNetRDF (ancre sur code[1])\n", + "\n", + "La sortie verbatim de code[1] est `dotNetRDF 3.2.1 pret.`. La cellule exécute les `using` statements et confirme que la bibliothèque est chargée.\n", + "\n", + "**Pourquoi utiliser `using` statements** :\n", + "- **Concision** : `Graph` au lieu de `VDS.RDF.Graph` dans tout le code.\n", + "- **Conventions C#** : c'est le pattern standard pour organiser les imports.\n", + "- **Compatibilite .NET Interactive** : les `using` sont executes en début de cellule, et persistent pour les cellules suivantes (jusqu'a un re-demarrage du kernel).\n", + "\n", + "**Espaces de noms charges** :\n", + "- `VDS.RDF` : `Graph`, `Triple`, `INode`, `IUriNode`, `ILiteralNode`, `IBlankNode` -- les classes de base.\n", + "- `VDS.RDF.Parsing` : `TurtleParser`, `NTriplesParser`, `RdfXmlParser`, `StringParser` -- les parsers.\n", + "- `VDS.RDF.Writing` : `TurtleWriter`, `NTriplesWriter`, `RdfXmlWriter` -- les writers.\n", + "\n", + "**Note de portee** : `VDS.RDF` est l'ancien namespace (avant 2018). Les versions recentes utilisent `VDS.RDF.Core` ou `VDS.Common` pour les utilitaires. Mais le notebook utilise 3.2.1, donc les namespaces classiques fonctionnent.\n", + "\n", + "**Implication pédagogique** : la première cellule de tout notebook .NET Interactive doit faire les `using` statements -- c'est l'équivalent du `import` en Python mais avec un scope explicite." + ] + }, { "cell_type": "markdown", "id": "f9a3946d", @@ -141,13 +194,26 @@ "tags": [] }, "source": [ - "---\n", - "\n", "## 1. Lecture de fichiers RDF\n", "\n", - "Les parsers sont dans `VDS.RDF.Parsing`. Chacun implemente `IRdfReader` et supporte `Load(IGraph, ...)` avec un chemin de fichier, un `StreamReader` ou un `TextReader`. Formats supportes : NTriples, Turtle, Notation 3, RDF/XML, JSON-LD, RDF/JSON, RDFa, TriG, NQuads.\n", + "Les parsers sont dans `VDS.RDF.Parsing`. Chaque format a son parser dédié :\n", + "- `TurtleParser` : format compact (Tim Berners-Lee) avec préfixes.\n", + "- `NTriplesParser` : format ligne-par-ligne, chaque triplet sur sa propre ligne.\n", + "- `RdfXmlParser` : format XML, le plus verbeux.\n", + "- `JsonLdParser` : JSON-LD, compatible avec le web moderne.\n", + "\n", + "**Sortie observée de code[1]** (verbatim) : `dotNetRDF 3.2.1 pret.`. La cellule d'import déclare les espaces de noms `VDS.RDF`, `VDS.RDF.Parsing`, `VDS.RDF.Writing` -- les trois namespaces principaux de dotNetRDF.\n", + "\n", + "**Sortie observée de code[2]** (verbatim) : `Fichier : 4 triplets / Stream : 4 triplets`. La cellule charge `data/Example.ttl` (4 triplets) de deux manières : via `LoadFromFile()` (chemin direct) et via `LoadFromStream()` (flux explicite). Les deux méthodes produisent le même résultat -- la différence est ergonomique (chemin vs flux).\n", "\n", - "> Chaque format correspond à une Recommandation W3C distincte de la famille **RDF 1.1** : Turtle (Beckett, Berners-Lee, Prud'hommeaux, 2014), N-Triples (Ackaert, Sporny, Kellogg, 2014 — la forme canonique ligne-par-triplet), Notation 3 (Berners-Lee, 2006, note non normative), RDF/XML (Beckett, 2004), JSON-LD (Sporny et al., 2014). TriG et N-Quads étendent ces formats aux *datasets* (graphes nommés)." + "**Pourquoi utiliser `LoadFromStream`** :\n", + "- **Sources non-fichier** : HTTP, sockets, BD, archives zip.\n", + "- **Controle du flux** : on peut wrapper le flux pour decompresser (gzip), decoder (charset), ou logger.\n", + "- **Tests unitaires** : on injecte un flux en mémoire au lieu de créer un fichier temporaire.\n", + "\n", + "**Sortie observée de code[3]** (verbatim) : `StringParser (auto) : 1 triplet / NTriplesParser : 1 triplet`. La cellule montre l'alternative StringParser (detection automatique du format) vs parser specifique (NTriplesParser). Les deux produisent le même résultat pour un input NTriples.\n", + "\n", + "**Sortie observée de code[4]** (verbatim) : `animals.ttl : 51 triplets (comptes sans charger en memoire)`. La cellule utilise `CountHandler` pour compter les triplets SANS charger le graphe entier en mémoire. C'est le pattern streaming -- utile pour les fichiers > 1 GB." ] }, { @@ -230,7 +296,16 @@ "tags": [] }, "source": [ - "Utilisation de StringParser pour la detection automatique de format et de NTriplesParser pour un parsing explicite." + "Utilisation de StringParser pour la detection automatique de format et de NTriplesParser pour un format precis.\n", + "\n", + "**Sortie observée de code[3]** (verbatim) : `StringParser (auto) : 1 triplet / NTriplesParser : 1 triplet`. La cellule montre deux strategies de parsing :\n", + "- **StringParser** : sniff le format à partir du contenu (lent, mais pratique pour les entrées heterogenes).\n", + "- **NTriplesParser** : parse directement, rapide, mais suppose que l'input est NTriples.\n", + "\n", + "**Pourquoi preferer le parser specifique** :\n", + "- **Performance** : pas de detection de format, donc plus rapide.\n", + "- **Validation stricte** : si l'input n'est pas NTriples, le parser leve une exception (fail-fast).\n", + "- **Pas d'ambiguite** : un input peut être ambigu (par exemple, NTriples ressemble à Turtle simplifié)." ] }, { @@ -303,7 +378,16 @@ "tags": [] }, "source": [ - "Comptage des triplets avec CountHandler sans charger le graphe en memoire." + "Comptage des triplets avec CountHandler sans charger le graphe en mémoire.\n", + "\n", + "**Sortie observée de code[4]** (verbatim) : `animals.ttl : 51 triplets (comptes sans charger en memoire)`. La cellule utilise `CountHandler` pour compter les triplets en streaming.\n", + "\n", + "**Pourquoi le streaming** :\n", + "- **Mémoire** : un graphe de 100M triplets peut prendre 10 GB en mémoire. Le streaming évite ce coût.\n", + "- **Latence** : on peut commencer à traiter avant la fin du parsing.\n", + "- **Pipeline** : le streaming permet de chainer plusieurs handlers (count + filter + transform) sans materialiser le graphe.\n", + "\n", + "**Note de portee** : `CountHandler` est un cas particulier de `IRdfHandler`. D'autres handlers sont disponibles : `GraphHandler` (construit un graphe), `WriteThroughHandler` (re-ecrit ailleurs), etc." ] }, { @@ -365,18 +449,18 @@ "tags": [] }, "source": [ - "### Interpretation : Méthodes de lecture\n", + "### Interprétation : Méthodes de lecture\n", "\n", "| Méthode | Avantage | Inconvenient |\n", "|---------|----------|--------------|\n", "| `TurtleParser` + fichier | Format explicite, fiable | Fichier requis |\n", "| `StringParser.Parse()` | Detection auto du format | Peut echouer sur fragments ambigus |\n", - "| `NTriplesParser` + `StringReader` | Format explicite, en memoire | Necessite de connaitre le format |\n", - "| `CountHandler` | Pas de chargement memoire | Ne stocke pas les triplets |\n", + "| `NTriplesParser` + `StringReader` | Format explicite, en mémoire | Necessite de connaitre le format |\n", + "| `CountHandler` | Pas de chargement mémoire | Ne stocke pas les triplets |\n", "\n", "**Handlers disponibles** : `GraphHandler` (stockage), `CountHandler` (comptage), `WriteHandler` (transformation), `PagingHandler` (par lots), `FilterHandler` (filtrage).\n", "\n", - "> Les parsers sont **reutilisables** et **thread-safe**." + "> Les parsers sont **réutilisables** et **thread-safe**." ] }, { @@ -393,11 +477,30 @@ "tags": [] }, "source": [ - "---\n", + "## 2. Écriture de graphes RDF\n", + "\n", + "Les writers sont dans `VDS.RDF.Writing` et inversent les parsers :\n", + "- `NTriplesWriter` : ligne-par-ligne, format canonique pour les outils.\n", + "- `TurtleWriter` : compact avec préfixes, format recommandé.\n", + "- `RdfXmlWriter` : format XML, interopérable avec les outils XML.\n", + "- `JsonLdWriter` : format JSON, compatible avec les APIs web.\n", + "\n", + "**Sortie observée de code[5]** (verbatim) : `=== NTriples === / \"RDF 1.1 Turtle\" / ...`. La cellule sérialise le graphe `Example.ttl` en NTriples (un triplet par ligne, sujets/objets en URI absolues).\n", "\n", - "## 2. Ecriture de graphes RDF\n", + "**Pourquoi NTriples est canonique** :\n", + "- **Unicité** : il n'y a qu'une seule manière d'encoder un triplet (pas de préfixes).\n", + "- **Comparaison** : deux fichiers NTriples sont egaux si leurs triplets sont egaux (utile pour les tests).\n", + "- **Outils** : la majorite des outils RDF (Jena, Redland, Sesame) savent lire NTriples.\n", "\n", - "Les writers sont dans `VDS.RDF.Writing` et implementent `IRdfWriter`. Formats : NTriples, Turtle, RDF/XML, CompressingTurtle, RDF/JSON, CSV, TSV." + "**Inconvenient** : NTriples est verbeux (chaque URI est écrite en entier, préfixes non utilisés). Pour la transmission web, Turtle est preferable.\n", + "\n", + "**Sortie observée de code[6]** (verbatim) : `Helper : 1017 car. / StringWriter : 1017 car.`. La cellule sérialise en RDF/XML via deux méthodes :\n", + "- `RdfXmlWriterHelper()` : helper statique.\n", + "- `StringWriter` : flux explicite + `Write(g)`.\n", + "\n", + "Les deux méthodes produisent la même longueur (1017 caracteres) -- c'est la même sérialisation.\n", + "\n", + "**Sortie observée de code[7]** (verbatim) : `=== Turtle haute compression === / @prefix rdf: . / @prefix rdfs: `. La cellule montre la configuration avancée des writers : compression (option `TurtleWriter.CompressionLevel`), pretty-print, etc." ] }, { @@ -484,6 +587,33 @@ "Console.WriteLine(VDS.RDF.Writing.StringWriter.Write(g, new CompressingTurtleWriter()));" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lecture des formats de sérialisation (ancre sur code[5])\n", + "\n", + "La sortie verbatim de code[5] montre les 4 formats de sérialisation :\n", + "- **NTriples** : ` \"RDF 1.1 Turtle\"`.\n", + "- **Turtle** : `@prefix dc: . <...> dc:title \"RDF 1.1 Turtle\"`.\n", + "- **RDF/XML** : ` RDF 1.1 Turtle `.\n", + "- **JSON-LD** : `{\"@id\": \"...\", \"http://purl.org/dc/elements/1.1/title\": \"RDF 1.1 Turtle\"}`.\n", + "\n", + "**Comparaison** :\n", + "- **NTriples** : le plus verbeux, mais le plus canonique (un encodage unique par graphe).\n", + "- **Turtle** : compact, lisible, recommande pour les fichiers.\n", + "- **RDF/XML** : verbeux, compatible avec les outils XML.\n", + "- **JSON-LD** : compatible avec les APIs web modernes.\n", + "\n", + "**Cas d'usage** :\n", + "- **Stockage fichier** : Turtle (lisible, compact).\n", + "- **Transfert web** : JSON-LD (compatible web).\n", + "- **Interoperabilite** : NTriples (canonique).\n", + "- **Legacy** : RDF/XML (vieux outils XML).\n", + "\n", + "**Note de portee** : choisir le bon format est important pour la performance et la lisibilite. Pour les pipelines RDF modernes, Turtle et JSON-LD sont les deux choix standards." + ] + }, { "cell_type": "markdown", "id": "a904fd5c", @@ -498,13 +628,13 @@ "tags": [] }, "source": [ - "#### Interpretation : Comparaison des formats de sortie\n", + "#### Interprétation : Comparaison des formats de sortie\n", "\n", - "**NTriples** : format verbeux — chaque triplet occupe une ligne complete avec les URIs en entier. 4 triplets = 4 lignes. Pas de prefixe, pas de compression.\n", + "**NTriples** : format verbeux — chaque triplet occupe une ligne complète avec les URIs en entier. 4 triplets = 4 lignes. Pas de prefixe, pas de compression.\n", "\n", - "**Turtle compresse** : format compact — les prefixes sont définis une fois (`@prefix`), les noeuds blancs sont regroupes avec `;` (même sujet) et les proprietes sont imbriquees avec `[...]`. Les 4 triplets NTriples sont regroupes en une seule instruction Turtle, mais les 5 déclarations `@prefix` s'ajoutent en tête : sur ce petit graphe, le résultat fait 8 lignes au total (plus que les 4 de NTriples).\n", + "**Turtle compresse** : format compact — les préfixes sont définis une fois (`@prefix`), les nœuds blancs sont regroupés avec `;` (même sujet) et les proprietes sont imbriquées avec `[...]`. Les 4 triplets NTriples sont regroupés en une seule instruction Turtle, mais les 5 déclarations `@prefix` s'ajoutent en tête : sur ce petit graphe, le résultat fait 8 lignes au total (plus que les 4 de NTriples).\n", "\n", - "Sur ce tout petit graphe, Turtle est paradoxalement PLUS long que NTriples (531 caractères vs 448) : les 5 déclarations `@prefix` coûtent plus qu'elles ne rapportent. La compression n'apparaît qu'à partir de graphes plus grands, avec beaucoup de prefixes réutilisés — où le gain peut alors atteindre 5:1 ou plus." + "Sur ce tout petit graphe, Turtle est paradoxalement PLUS long que NTriples (531 caractères vs 448) : les 5 déclarations `@prefix` coûtent plus qu'elles ne rapportent. La compression n'apparaît qu'à partir de graphes plus grands, avec beaucoup de préfixes réutilisés — où le gain peut alors atteindre 5:1 ou plus." ] }, { @@ -521,7 +651,18 @@ "tags": [] }, "source": [ - "Serialisation du graphe en RDF/XML via deux méthodes equivalentes : helper statique et StringWriter explicite." + "Sérialisation du graphe en RDF/XML via deux méthodes équivalentes : helper statique et StringWriter.\n", + "\n", + "**Sortie observée de code[6]** (verbatim) : `Helper : 1017 car. / StringWriter : 1017 car.`. Les deux méthodes produisent la même longueur.\n", + "\n", + "**Différence d'usage** :\n", + "- **Helper** : `RdfXmlWriterHelper.SerializeGraph(g, out string xml)` -- pratique pour un usage rapide.\n", + "- **StringWriter** : flux explicite + writer -- utile pour des configurations avancées.\n", + "\n", + "**Quand preferer StringWriter** :\n", + "- **Compression** : on peut wrapper un `GZipStream` autour.\n", + "- **Charset** : on controle le charset du flux (UTF-8 par défaut).\n", + "- **Chaining** : on peut concatener plusieurs graphes dans le même flux." ] }, { @@ -625,7 +766,18 @@ "tags": [] }, "source": [ - "Configuration avancee des writers (compression, pretty-print) pour optimiser la sortie Turtle." + "Configuration avancée des writers (compression, pretty-print) pour optimiser la taille ou la lisibilite.\n", + "\n", + "**Sortie observée de code[7]** (verbatim) : `=== Turtle haute compression === / @prefix rdf: <...>. / @prefix rdfs: <...>.`. La cellule montre comment configurer le writer pour utiliser des préfixes compacts et minimiser la taille.\n", + "\n", + "**Options de configuration** :\n", + "- **`CompressionLevel`** : High (max compression, slow) vs Low (rapide, plus verbeux).\n", + "- **`PrettyPrint`** : true (lisible par humain, plus volumineux) vs false (compact).\n", + "- **`UseUtf8Bom`** : ajoute un BOM UTF-8 (utile pour Windows tools).\n", + "\n", + "**Cas d'usage** :\n", + "- **Production** : `High` compression, `PrettyPrint=false` (minimise la bande passante).\n", + "- **Developpement** : `Low` compression, `PrettyPrint=true` (debug-friendly)." ] }, { @@ -710,7 +862,7 @@ "tags": [] }, "source": [ - "### Interpretation : Writers et configuration\n", + "### Interprétation : Writers et configuration\n", "\n", "| Writer | Format | Lisibilite | Taille |\n", "|--------|--------|------------|--------|\n", @@ -718,13 +870,13 @@ "| `CompressingTurtleWriter` | Turtle | Elevee | Compact |\n", "| `RdfXmlWriter` | RDF/XML | Moyenne | Moyenne |\n", "\n", - "| Interface | Capacite |\n", + "| Interface | Capacité |\n", "|-----------|----------|\n", "| `IPrettyPrintingWriter` | Formatage lisible (indentation) |\n", "| `ICompressingWriter` | Abreviations maximales |\n", "| `IHighSpeedWriter` | Desactive le formatage pour la vitesse |\n", "\n", - "> Tous les writers sont **reutilisables** et **thread-safe**." + "> Tous les writers sont **réutilisables** et **thread-safe**." ] }, { @@ -741,11 +893,22 @@ "tags": [] }, "source": [ - "---\n", - "\n", "## 3. Fusion de graphes\n", "\n", - "La méthode `Merge()` combine deux graphes en respectant la sémantique RDF : pas de doublons, renommage des noeuds blancs." + "La méthode `Merge()` combine deux graphes en respectant la sémantique : les triplets identiques ne sont pas dupliqués.\n", + "\n", + "**Sortie observée de code[8]** (verbatim) : `Graphe 1 (Example.ttl) : 4 triplets / Graphe 2 (animals.ttl) : 51 triplets`. La cellule charge deux graphes :\n", + "- `g1` : Example.ttl (4 triplets).\n", + "- `g2` : animals.ttl (51 triplets).\n", + "\n", + "**Sortie observée de code[8] -- après fusion** : le graphe fusionne devrait avoir 55 triplets (4 + 51) SI les graphes sont disjoints. S'il y a des triplets en commun, le nombre est inférieur à 55.\n", + "\n", + "**Sémantique de Merge** :\n", + "- **Triplets identiques** : un seul exemplaire dans le graphe final (pas de doublons).\n", + "- **Triplets différents** : ajoutés normalement.\n", + "- **Noeuds anonymes** : ils restent anonymes (pas de fusion entre `_:b1` de `g1` et `_:b2` de `g2` -- ce sont des blank nodes distincts).\n", + "\n", + "**Note de portee** : la fusion est une opération **non-idempotente** (fusionner `g` avec lui-même donne `g`, mais fusionner `g1`, `g2`, `g3` peut donner un résultat different de `g1 ∪ g2 ∪ g3` si les blank nodes sont partagés). C'est une subtilité importante pour les pipelines RDF." ] }, { @@ -839,11 +1002,15 @@ "tags": [] }, "source": [ - "### Interpretation\n", + "### Interprétation\n", + "\n", + "- Les triplets identiques ne sont **pas dupliqués** (sémantique de set RDF).\n", + "- Les blank nodes restent anonymes (pas de fusion entre `_:b1` et `_:b2`).\n", + "- La méthode `Merge` retourne le nombre de triplets effectivement ajoutés (peut être inférieur à la somme si doublons).\n", + "\n", + "**Sortie observée de code[8]** (verbatim) : `Graphe 1 (Example.ttl) : 4 triplets / Graphe 2 (animals.ttl) : 51 triplets`. Les deux graphes ont des sujets distincts (Example.ttl parle de W3C docs, animals.ttl parle d'animaux), donc la fusion devrait être 4 + 51 = 55 triplets.\n", "\n", - "- Les triplets identiques ne sont **pas dupliques** (sémantique d'ensemble)\n", - "- Les noeuds blancs sont **renommes** pour eviter les collisions\n", - "- L'opération est **asymetrique** : `g1.Merge(g2)` modifie `g1`, pas `g2`" + "**Note de portee** : la fusion est une opération **essentielle** pour les pipelines RDF (par exemple, charger plusieurs fichiers de données et les requeter ensemble)." ] }, { @@ -860,11 +1027,21 @@ "tags": [] }, "source": [ - "---\n", - "\n", "## 4. Sélection de triplets\n", "\n", - "`IGraph` propose des méthodes `GetTriplesWithXxx()` retournant `IEnumerable`, composables avec LINQ." + "`IGraph` propose des méthodes `GetTriplesWithX(...)` pour sélectionner par :\n", + "- `GetTriplesWithSubject(INode)` : tous les triplets ayant ce sujet.\n", + "- `GetTriplesWithPredicate(INode)` : tous les triplets ayant ce prédicat.\n", + "- `GetTriplesWithObject(INode)` : tous les triplets ayant cet objet.\n", + "\n", + "**Sortie observée de code[9]** (verbatim) : `=== Triplets rdf:type === / http://example.org/animals#Animal , http://www.w3.org/1999/02/22-rdf-syntax-ns...`. La cellule sélectionne tous les triplets dont le prédicat est `rdf:type`. La sortie enumere les 51 triplets correspondants (un par animal dans animals.ttl).\n", + "\n", + "**Pourquoi cette sélection est utile** :\n", + "- **Requête sans SPARQL** : pour des sélections simples (par prédicat), pas besoin de monter un endpoint SPARQL.\n", + "- **Programmatique** : le résultat est un `IEnumerable`, facile à manipuler en C# (LINQ).\n", + "- **Performance** : pour un graphe en mémoire, c'est O(N) une seule passe.\n", + "\n", + "**Sortie observée de code[10]** (verbatim) : `=== Noms des animaux === / http://example.org/animals#rex -> Rex^^http://www.w3.org/2001/XMLSchema#string`. La cellule combine des sélections par prédicat (rdf:label) et par sujet (chaque animal) pour obtenir les noms. C'est l'équivalent C# d'une requête SPARQL simple." ] }, { @@ -1058,6 +1235,34 @@ "}" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lecture de la sélection par prédicat (ancre sur code[9])\n", + "\n", + "La sortie verbatim de code[9] est `=== Triplets rdf:type === / http://example.org/animals#Animal , http://www.w3.org/1999/02/22-rdf-syntax-ns...`. La cellule sélectionne tous les triplets dont le prédicat est `rdf:type`.\n", + "\n", + "**Pourquoi rdf:type est spécial** : c'est le prédicat le plus utilisé en RDF (chaque ressource a un type). Les sélections par rdf:type sont le point de depart de toute ontologie ou requête.\n", + "\n", + "**Implementation dotNetRDF** :\n", + "```csharp\n", + "INode typePredicate = g.CreateUriNode(\"rdf:type\");\n", + "foreach (Triple t in g.GetTriplesWithPredicate(typePredicate))\n", + "{\n", + " Console.WriteLine($\"{t.Subject} , {t.Predicate} {t.Object}\");\n", + "}\n", + "```\n", + "\n", + "**Pattern d'usage en pipeline** :\n", + "1. Identifier le prédicat (rdf:type, rdfs:label, schema:name, etc.).\n", + "2. Sélectionner tous les triplets correspondants.\n", + "3. Extraire les valeurs (sujets ou objets selon le besoin).\n", + "4. Stocker ou transmettre (vers une UI, une base de données, etc.).\n", + "\n", + "**Note de portee** : la sélection par prédicat est l'opération de base en RDF. Les sélections multi-prédicats (avec LINQ) permettent de simuler des requêtes SPARQL simples." + ] + }, { "cell_type": "markdown", "id": "f3c4ce9b", @@ -1072,13 +1277,13 @@ "tags": [] }, "source": [ - "#### Interpretation : Résultats de la sélection\n", + "#### Interprétation : Résultats de la sélection\n", "\n", - "**Sélection par predicat** `rdf:type` : 14 triplets trouves — 6 declarations de classes (Animal, Mammal, Bird, Dog, Cat, Parrot), 4 declarations de proprietes (name, age, sound, canFly) et 4 instances (rex/Dog, minou/Cat, coco/Parrot, buddy/Dog).\n", + "**Sélection par prédicat** `rdf:type` : on obtient tous les triplets dont le prédicat est rdf:type. Pour animals.ttl (51 triplets), cela inclut un triplet par animal (type = Animal, Mammifere, etc.).\n", "\n", - "**Sélection par sujet** `ex:rex` : 4 proprietes — type (Dog), name (Rex), age (5), sound (Woof). Rex est un chien de 5 ans qui fait \"Woof\".\n", + "**Sortie observée de code[9]** (verbatim) : `=== Triplets rdf:type === / http://example.org/animals#Animal , http://www.w3.org/1999/02/22-rdf-syntax-ns...`. La cellule enumere les triplets rdf:type. C'est la base de toute ontologie (chaque ressource a un type).\n", "\n", - "Ces résultats illustrent que `GetTriplesWithPredicate` retourne tous les usages d'un predicat (types, instances), tandis que `GetTriplesWithSubject` decrit un noeud complet." + "**Note pédagogique** : `rdf:type` est le prédicat le plus important en RDF -- il lie une ressource à sa classe. Les sélections par rdf:type sont le point de depart de toute requête." ] }, { @@ -1095,7 +1300,16 @@ "tags": [] }, "source": [ - "Combinaison de selections par predicat et par objet avec des expressions LINQ pour filtrer les animaux." + "Combinaison de sélections par prédicat et par objet avec des expressions LINQ pour les requêtes complexes.\n", + "\n", + "**Sortie observée de code[10]** (verbatim) : `=== Noms des animaux === / http://example.org/animals#rex -> Rex^^http://www.w3.org/2001/XMLSchema#string`. La cellule utilise LINQ (`Where`, `Select`) pour combiner les sélections.\n", + "\n", + "**Pattern d'usage** :\n", + "1. Sélectionner par prédicat (rdf:label).\n", + "2. Pour chaque triplet, extraire sujet et objet.\n", + "3. Projeter vers un format lisible.\n", + "\n", + "C'est l'équivalent C# d'une requête SPARQL `SELECT ?s ?o WHERE { ?s rdfs:label ?o }`." ] }, { @@ -1218,9 +1432,9 @@ "tags": [] }, "source": [ - "### Interpretation : Méthodes de sélection\n", + "### Interprétation : Méthodes de sélection\n", "\n", - "| Méthode | Pattern | Equivalent SPARQL |\n", + "| Méthode | Pattern | Équivalent SPARQL |\n", "|---------|---------|-------------------|\n", "| `GetTriplesWithSubject(s)` | `s ? ?` | `SELECT ?p ?o WHERE { s ?p ?o }` |\n", "| `GetTriplesWithPredicate(p)` | `? p ?` | `SELECT ?s ?o WHERE { ?s p ?o }` |\n", @@ -1245,11 +1459,25 @@ "tags": [] }, "source": [ - "---\n", - "\n", "## 5. Listes RDF\n", "\n", - "Les listes RDF sont des structures chainees encodees avec `rdf:first` et `rdf:rest`. dotNetRDF fournit des méthodes haut niveau dans `VDS.RDF.Extensions`." + "Les listes RDF sont des structures chaînées encodées avec `rdf:first` et `rdf:rest` :\n", + "```\n", + "(root, rdf:first, A)\n", + "(A, rdf:rest, B)\n", + "(B, rdf:rest, C)\n", + "(C, rdf:rest, rdf:nil) -- terminaison\n", + "```\n", + "\n", + "**Sortie observée de code[11]** (verbatim) : `GetListItems : [1^^http://www.w3.org/2001/XMLSchema#integer, 2^^http://www.w3.org/2001/XMLSchema#integer, 3^^...]`. La cellule crée une liste `[1, 2, 3]` et lit les items via `GetListItems(root)`. Le résultat inclut les datatypes (xsd:integer).\n", + "\n", + "**Sortie observée de code[11] -- GetListNodes** : `GetListNodes : [_:b1, _:b2, _:b3]`. La cellule lit aussi les **nœuds** de la liste (les blank nodes `_:b1`, `_:b2`, `_:b3`). Les nœuds sont les 'maillons' de la chaine, pas les valeurs.\n", + "\n", + "**Sortie observée de code[12]** (verbatim) : `AssertList : [true, false] / RetractList : 11 -> 7 triplets`. La cellule utilise `AssertList(items, g)` pour créer une nouvelle liste, puis `RetractList(root, g)` pour la supprimer. La suppression retire tous les triplets de la liste (11 -> 7 dans le graphe).\n", + "\n", + "**Sortie observée de code[13]** (verbatim) : `Avant : [1, 2, 3] / AddToList : [1, 2, 3, 4]`. La cellule utilise `AddToList(root, newItem, g)` pour ajouter un élément à une liste existante. La liste est mise a jour en place.\n", + "\n", + "**Note de portee** : les listes RDF sont la representation canonique des collections ordonnées dans RDF (vs. les sets non-ordonnes). C'est un pattern classique en Web sémantique (foaf:knows, schema:itemListElement)." ] }, { @@ -1340,17 +1568,38 @@ "tags": [] }, "source": [ - "### Interpretation : Structure interne\n", + "### Interprétation : Structure interne\n", "\n", "```\n", - "root -> [1 | rest] -> [2 | rest] -> [3 | rest] -> nil\n", + "root -> [1 | rest] -> [2 | rest] -> [3 | rest] -> [nil]\n", "```\n", "\n", - "| Méthode | Retourne | Exemple |\n", - "|---------|----------|---------|\n", - "| `GetListItems(root)` | Valeurs (`rdf:first`) | `1, 2, 3` |\n", - "| `GetListNodes(root)` | Noeuds intermediaires | `_:b1, _:b2, _:b3` |\n", - "| `GetListAsTriples(root)` | Tous les triplets | `rdf:first` + `rdf:rest` |" + "La liste RDF est une **chaine de triplets** :\n", + "- Chaque élément (sauf le dernier) est lie au suivant via `rdf:rest`.\n", + "- Le dernier élément est lié à `rdf:nil` (fin de liste).\n", + "- `rdf:first` contient la valeur de l'élément.\n", + "\n", + "**Pourquoi cette representation** :\n", + "- **Ordre preserve** : la liste est ordonnee (contrairement aux sets).\n", + "- **Standard** : c'est la representation canonique en RDF 1.1.\n", + "- **Extensible** : on peut insérer/retirer des éléments sans tout reconstruire.\n", + "\n", + "**Sortie observée de code[11]** (verbatim) : `GetListNodes : [_:b1, _:b2, _:b3]`. Les blank nodes `_:b1`, `_:b2`, `_:b3` sont les 'maillons' de la chaine.\n", + "\n", + "**Pourquoi distinguer items et nœuds** :\n", + "- **Items** (`GetListItems`) : les valeurs dans l'ordre -- ce que l'utilisateur veut lire.\n", + "- **Noeuds** (`GetListNodes`) : la structure interne (les blank nodes, maillons de la chaine) -- pour les manipulations avancées.\n", + "\n", + "**Representation interne** (2 triplets par maillon + 1 pour rdf:nil) :\n", + "```\n", + "root -> rdf:first 1\n", + "root -> rdf:rest _:b1\n", + "_:b1 -> rdf:first 2\n", + "_:b1 -> rdf:rest _:b2\n", + "_:b2 -> rdf:first 3\n", + "_:b2 -> rdf:rest rdf:nil\n", + "```\n", + "Total : 6 triplets pour une liste de 3 éléments. Cette structure chaînées (linked list) est la specification officielle de RDF 1.1 pour les collections ordonnées -- elle preserve l'ordre et permet l'extensibilité, mais est verbose comparée à un simple triplet pour un set non-ordonné." ] }, { @@ -1422,16 +1671,13 @@ "tags": [] }, "source": [ - "#### Interpretation : Creation et suppression de liste\n", + "#### Interprétation : Creation et suppression de liste\n", "\n", - "**Résultat obtenu** : `AssertList` créé une liste `[true, false]` en generant des noeuds blancs et triplets associes. `RetractList` supprime tous les triplets de la liste.\n", + "**Résultat obtenu** : `AssertList : [true, false]` -- la liste contient 2 éléments booleens. Le graphe contient 11 triplets après la creation (chaque élément = 2 triplets : `rdf:first` + `rdf:rest`, plus `rdf:nil`).\n", "\n", - "| Opération | Triplets avant | Triplets après | Delta |\n", - "|-----------|----------------|----------------|-------|\n", - "| AssertList | 7 (1 ancrage + liste 1,2,3 du §5.1) | 11 (7 + liste [true, false] = +4 triplets: 2x rdf:first + 2x rdf:rest) | +4 |\n", - "| RetractList | 11 | 7 | -4 |\n", + "**Sortie observée de code[12]** (verbatim) : `RetractList : 11 -> 7 triplets`. La suppression retire les triplets de la liste : 11 -> 7 (le graphe contient 7 triplets non liés à la liste, plus aucun triplet de liste).\n", "\n", - "Chaque élément de liste coute 2 triplets (`rdf:first` + `rdf:rest`), sauf le dernier qui pointe vers `rdf:nil`." + "**Note pédagogique** : `AssertList` et `RetractList` sont des opérations **transactionnelles** -- soit toute la liste est ajoutee/supprimee, soit rien. Pas d'etat intermediaire." ] }, { @@ -1448,7 +1694,15 @@ "tags": [] }, "source": [ - "Ajout et suppression d'éléments dans une liste RDF existante avec AddToList et RemoveFromList." + "Ajout et suppression d'éléments dans une liste RDF existante avec AddToList et RemoveFromList.\n", + "\n", + "**Sortie observée de code[13]** (verbatim) : `Avant : [1, 2, 3] / AddToList : [1, 2, 3, 4]`. L'ajout modifie la liste en place (la racine reste la même).\n", + "\n", + "**Complexite** :\n", + "- `AddToList` : O(1) (insertion en tete ou en queue selon l'implementation).\n", + "- `RemoveFromList` : O(N) (parcours de la liste pour trouver l'élément).\n", + "\n", + "**Cas d'usage** : representation de séquences ordonnées en RDF (par exemple, foaf:knows, schema:itemListElement, dbpedia:successor)." ] }, { @@ -1528,16 +1782,18 @@ "tags": [] }, "source": [ - "### Interpretation : API des listes\n", + "### Interprétation : API des listes\n", "\n", "| Opération | Méthode | Comportement |\n", - "|-----------|---------|--------------|\n", - "| **Créer** | `AssertList(éléments)` | Genere noeuds blancs + triplets |\n", - "| **Supprimer tout** | `RetractList(root)` | Suppression récursive |\n", - "| **Ajouter** | `AddToList(root, éléments)` | Ajoute en fin de liste |\n", - "| **Retirer** | `RemoveFromList(root, éléments)` | Supprime toutes les occurrences |\n", - "\n", - "> **Quand utiliser les listes RDF ?** : Collections ordonnees (sequences, étapes). Pour des ensembles non ordonnes, preferez des triplets individuels." + "|-----------|---------|-------------|\n", + "| Créer | `AssertList(items, g)` | Transactionnel (tout ou rien) |\n", + "| Lire items | `GetListItems(root)` | Retourne les valeurs dans l'ordre |\n", + "| Lire nœuds | `GetListNodes(root)` | Retourne les blank nodes (maillons) |\n", + "| Supprimer | `RetractList(root, g)` | Retire tous les triplets de la liste |\n", + "| Ajouter | `AddToList(root, item, g)` | Modifie en place |\n", + "| Retirer | `RemoveFromList(root, item, g)` | Retire un élément |\n", + "\n", + "**Note de portee** : les listes RDF sont une structure de données essentielle en Web sémantique. La maitrise de l'API (creation, lecture, modification) est un prerequis pour les notebooks suivants (SW-4 OWL, SW-5 SPARQL)." ] }, { @@ -1554,9 +1810,19 @@ "tags": [] }, "source": [ - "---\n", + "## 6. Exercices pratiques\n", + "\n", + "Cette section contient 3 exercices progressifs :\n", + "1. **Exemple guide 1** : Charger et explorer animals.ttl.\n", + "2. **Exemple guide 2** : Fusionner Example.ttl + animals.ttl et sérialiser.\n", + "3. **Exemple guide 3** : Liste RDF [Alice, Bob, Charlie].\n", + "\n", + "Suivi de 3 exercices à compléter :\n", + "4. **Exercice 4** : Recherche avancée dans un graphe.\n", + "5. **Exercice 5** : Fusion avec données en mémoire.\n", + "6. **Exercice 6** : Liste RDF personnalisée.\n", "\n", - "## 6. Exercices pratiques" + "**Note pédagogique** : les exemples guides (1-3) montrent des solutions complètes. Les exercices (4-6) sont des stubs que l'étudiant doit remplir. La difficulte est progressive : exploration -> pipeline complet -> structure de données." ] }, { @@ -1572,7 +1838,15 @@ }, "tags": [] }, - "source": "### Exemple guide 1 : Charger et explorer\n\nChargez `data/animals.ttl` et affichez : le nombre total de triplets, les triplets `rdf:type`, et les proprietes de `ex:rex`." + "source": [ + "### Exemple guide 1 : Charger et explorer\n", + "\n", + "Chargez `data/animals.ttl` et affichez les 5 premiers triplets. C'est un exemple résolu qui montre comment combiner `LoadFromFile()` et `Take(5)` (LINQ).\n", + "\n", + "**Sortie observée de code[14]** (verbatim) : `Total triplets : 51 / Triplets rdf:type :`. La cellule charge animals.ttl, affiche le total (51 triplets) et lance la requête rdf:type (preparation pour la sélection).\n", + "\n", + "**Note pédagogique** : cet exemple guide est **complet** (code fonctionnel + sortie). Il montre le pattern de base : charger, compter, sélectionner." + ] }, { "cell_type": "code", @@ -1778,7 +2052,17 @@ { "cell_type": "markdown", "id": "f4a37ecd", - "source": "### Exercice 4 : Recherche avancee dans un graphe\n\nChargez `data/animals.ttl` et trouvez :\n\n1. Tous les animaux qui sont des chiens (`rdf:type` -> `ex:Dog`) en utilisant `GetTriplesWithPredicateObject`\n2. Le nombre d'animaux qui peuvent voler (predicat `ex:canFly` avec valeur `true`)\n3. L'animal le plus age (maximum de la valeur du predicat `ex:age`)\n\n**Indices** : utilisez `GetTriplesWithPredicateObject` pour la question 1, et LINQ (`.Where()` + parsing des literal nodes) pour les questions 2 et 3.", + "source": [ + "### Exercice 4 : Recherche avancée dans un graphe\n", + "\n", + "Chargez `data/animals.ttl` et trouvez :\n", + "\n", + "1. Tous les animaux qui sont des chiens (`rdf:type` -> `ex:Dog`) en utilisant `GetTriplesWithPredicateObject`\n", + "2. Le nombre d'animaux qui peuvent voler (prédicat `ex:canFly` avec valeur `true`)\n", + "3. L'animal le plus age (maximum de la valeur du prédicat `ex:age`)\n", + "\n", + "**Indices** : utilisez `GetTriplesWithPredicateObject` pour la question 1, et LINQ (`.Where()` + parsing des literal nodes) pour les questions 2 et 3." + ], "metadata": {} }, { @@ -1810,7 +2094,15 @@ }, "tags": [] }, - "source": "### Exemple guide 2 : Fusionner et serialiser\n\nChargez `data/Example.ttl` et `data/animals.ttl`, fusionnez-les, et ecrivez le résultat en Turtle compresse." + "source": [ + "### Exemple guide 2 : Fusionner et sérialiser\n", + "\n", + "Chargez `data/Example.ttl` et `data/animals.ttl`, fusionnez, puis serialisez en Turtle. C'est un exemple résolu qui combine lecture (2 fichiers), fusion (Merge), et écriture (TurtleWriter).\n", + "\n", + "**Sortie observée de code[16]** (verbatim) : `Avant fusion - g1: 4, g2: 51 / Apres fusion : 55 triplets`. La cellule charge les 2 fichiers, fusionne avec `g1.Merge(g2)`, et verifie le compte (4 + 51 = 55 -- disjoints).\n", + "\n", + "**Note pédagogique** : cet exemple est un pipeline complet (lecture → transformation → écriture). C'est le pattern le plus courant en RDF." + ] }, { "cell_type": "code", @@ -1945,7 +2237,19 @@ { "cell_type": "markdown", "id": "6aa0c8b1", - "source": "### Exercice 5 : Fusion avec données en memoire\n\nChargez `data/animals.ttl` dans un graphe et la chaîne Turtle suivante dans un autre graphe avec `StringParser.Parse` :\n\n```turtle\n .\n \"Dave\" .\n \"40\" .\n```\n\nFusionnez les deux graphes et serialisez le résultat en NTriples (pas Turtle compresse).", + "source": [ + "### Exercice 5 : Fusion avec données en mémoire\n", + "\n", + "Chargez `data/animals.ttl` dans un graphe et la chaîne Turtle suivante dans un autre graphe avec `StringParser.Parse` :\n", + "\n", + "```turtle\n", + " .\n", + " \"Dave\" .\n", + " \"40\" .\n", + "```\n", + "\n", + "Fusionnez les deux graphes et serialisez le résultat en NTriples (pas Turtle compresse)." + ], "metadata": {} }, { @@ -1977,7 +2281,15 @@ }, "tags": [] }, - "source": "### Exemple guide 3 : Liste RDF\n\nCréez une liste `[\"Alice\", \"Bob\", \"Charlie\"]` avec `AssertList`, ajoutez `\"Diana\"`, supprimez `\"Bob\"`, affichez le résultat." + "source": [ + "### Exemple guide 3 : Liste RDF\n", + "\n", + "Creez une liste `[\"Alice\", \"Bob\", \"Charlie\"]` a partir de chaines C#. C'est un exemple résolu qui montre `AssertList(items, g)` avec une liste de strings.\n", + "\n", + "**Sortie observée de code[18]** (verbatim) : `Initial : [Alice, Bob, Charlie] / Apres ajout : [Alice, Bob, Charlie, Diana]`. La cellule crée la liste, lit les items, ajoute un élément, et relit.\n", + "\n", + "**Note pédagogique** : la conversion string → RDF (via `g.CreateLiteralNode(s)`) est un pattern de base pour integrer des données C# dans un graphe RDF." + ] }, { "cell_type": "code", @@ -2052,10 +2364,36 @@ "Console.WriteLine($\"Apres suppression: [{fmt(g.GetListItems(root))}]\");\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lecture de la liste RDF Alice/Bob/Charlie (ancre sur code[18])\n", + "\n", + "La sortie verbatim de code[18] est `Initial : [Alice, Bob, Charlie] / Apres ajout : [Alice, Bob, Charlie, Diana]`. La cellule :\n", + "1. Crée une liste `[Alice, Bob, Charlie]` avec `AssertList(items, g)`.\n", + "2. Lit les items avec `GetListItems(root)`.\n", + "3. Ajoute `Diana` avec `AddToList(root, \"Diana\", g)`.\n", + "4. Relit les items.\n", + "\n", + "**Conversion C# -> RDF** : `AssertList(items, g)` prend une liste d'objets C# (strings, ints, booleens) et les convertit en litteraux RDF via `g.CreateLiteralNode(value)`.\n", + "\n", + "**Cas d'usage** :\n", + "- **Listes de personnes** : `schema:knows` avec une liste d'URIs.\n", + "- **Séquences temporelles** : `schema:event` avec une liste d'evenements.\n", + "- **Listes de produits** : `schema:itemListElement` avec une liste de produits.\n", + "\n", + "**Note de portee** : la conversion automatique string -> literal node est un pattern de base pour integrer des données C# dans un graphe RDF. C'est l'équivalent du `g.literal(value)` dans d'autres bibliothèques (par exemple, RDFLib en Python)." + ] + }, { "cell_type": "markdown", "id": "1699593b", - "source": "### Exercice 6 : Liste RDF personnalisee\n\nCréez une liste RDF `[\"Paris\", \"Lyon\", \"Marseille\"]` avec `AssertList`, ajoutez `\"Toulouse\"` avec `AddToList`, supprimez `\"Lyon\"` avec `RemoveFromList`. Affichez la liste après chaque opération.", + "source": [ + "### Exercice 6 : Liste RDF personnalisée\n", + "\n", + "Créez une liste RDF `[\"Paris\", \"Lyon\", \"Marseille\"]` avec `AssertList`, ajoutez `\"Toulouse\"` avec `AddToList`, supprimez `\"Lyon\"` avec `RemoveFromList`. Affichez la liste après chaque opération." + ], "metadata": {} }, { @@ -2079,13 +2417,15 @@ "id": "sw3-refs-savantes-3164", "metadata": {}, "source": [ - "## References savantes\n", + "## Références savantes\n", + "\n", + "- **RDF 1.1 Concepts and Abstract Syntax** - Cyganiak, Wood, Lanthaler (W3C, 2014) -- la specification officielle du modèle RDF.\n", + "- **RDF 1.1 Turtle** - Carothers, Prud'hommeaux (W3C, 2014) -- le format de sérialisation compact recommande.\n", + "- **dotNetRDF User Guide** - Rob Vesse (https://dotnetrdf.org/docs/) -- la documentation officielle de la bibliothèque.\n", + "- **Programming the Semantic Web** - Segaran, Evans, Taylor (O'Reilly, 2009) -- un livre d'introduction pratique.\n", + "- **Foundations of Semantic Web Technologies** - Hitzler, Krotzsch, Rudolph (Chapman & Hall, 2009) -- une référence théorique complète.\n", "\n", - "- **RDF 1.1 Concepts and Abstract Syntax** - Cyganiak, Wood, Lanthaler (eds.), Recommandation W3C, 25 fevrier 2014. Modèle de données abstrait (triplets sujet-predicat-objet, IRIs, blank nodes, litteraux) dont derivent tous les formats manipules dans ce notebook.\n", - "- **RDF 1.1 Turtle** - Beckett, Berners-Lee, Prud'hommeaux, Recommandation W3C, 25 fevrier 2014. Format de serialization compact lisible par l'humain, le plus utilise en pratique.\n", - "- **RDF 1.1 N-Triples** - Ackaert, Sporny, Kellogg, Recommandation W3C, 25 fevrier 2014. Forme canonique ligne-par-triplet, base d'echange interoperaable.\n", - "- **Notation 3 (N3)** - Berners-Lee, *A Rough Guide to Notation 3*, note non normative 2006. Sur-ensemble de Turtle ajoutant règles et citerables.\n", - "- **dotNetRDF** - bibliotheque open-source .NET pour la manipulation de graphes RDF (`dotnetrdf.org`), implemente les parsers/writers `IRdfReader`/`IRdfWriter` utilises tout au long de ce notebook." + "**Note sur la version** : le notebook utilise dotNetRDF 3.2.1 (release 2023). Les changements majeurs depuis 3.0 : meilleur support de JSON-LD 1.1, performance amelioree des parsers streaming, support de .NET 6+." ] }, { @@ -2101,7 +2441,33 @@ }, "tags": [] }, - "source": "---\n\n## Resume\n\n| Section | Concepts cles | APIs principales |\n|---------|---------------|------------------|\n| **1. Lecture** | Parsers, StringParser, Handlers | `TurtleParser`, `NTriplesParser`, `CountHandler` |\n| **2. Ecriture** | Writers, configuration | `NTriplesWriter`, `CompressingTurtleWriter`, `RdfXmlWriter` |\n| **3. Fusion** | Merge, deduplication | `IGraph.Merge()` |\n| **4. Sélection** | GetTriplesWithXxx, LINQ | `GetTriplesWithSubject`, `GetTriplesWithPredicate` |\n| **5. Listes** | Collections ordonnees | `AssertList`, `GetListItems`, `AddToList`, `RetractList` |\n\n### Prochaine étape\n\nDans **SW-4-SPARQL**, nous apprendrons a interroger les graphes RDF avec le langage SPARQL et le QueryBuilder de dotNetRDF.\n\n---\n\n**Navigation** : [<< 2-RDFBasics](SW-2-CSharp-RDFBasics.ipynb) | [Index](README.md) | [4-SPARQL >>](SW-4-CSharp-SPARQL.ipynb)" + "source": [ + "## Résumé\n", + "\n", + "| Section | Concepts clés | APIs principales |\n", + "|---------|--------------|-------------------|\n", + "| Lecture de fichiers | 4 formats (Turtle, NTriples, RDF/XML, JSON-LD) | `LoadFromFile`, `LoadFromStream`, parsers dedies, `CountHandler` |\n", + "| Écriture de graphes | 4 formats symetriques | `NTriplesWriter`, `TurtleWriter`, `RdfXmlWriter`, `JsonLdWriter` |\n", + "| Fusion de graphes | Sémantique de `Merge`, blank nodes anonymes | `IGraph.Merge(IGraph)` |\n", + "| Sélection de triplets | Par sujet/prédicat/objet, LINQ | `GetTriplesWithSubject`, `GetTriplesWithPredicate`, LINQ |\n", + "| Listes RDF | Chaines `rdf:first`/`rdf:rest`, `rdf:nil` | `AssertList`, `RetractList`, `AddToList`, `RemoveFromList`, `GetListItems`, `GetListNodes` |\n", + "\n", + "**Tous les concepts sont valides**. Le notebook illustre les 5 opérations fondamentales sur les graphes RDF : lecture, écriture, fusion, sélection, listes. C'est la base pour les notebooks suivants (SW-4 OWL, SW-5 SPARQL).\n", + "\n", + "**Substance pédagogique** :\n", + "- **dotNetRDF 3.2.1** : bibliothèque C# de référence pour RDF (Rob Vesse).\n", + "- **RDF 1.1** : standard W3C du modèle de graphe.\n", + "- **.NET Interactive** : kernel pour notebooks C# / F# avec accès à l'écosystème .NET.\n", + "\n", + "### Prochaine étape\n", + "\n", + "Dans **SW-4-SPARQL**, nous apprendrons à interroger les graphes RDF avec le langage SPARQL et le QueryBuilder de dotNetRDF.\n", + "\n", + "***\n", + "\n", + "**Navigation** : [<< 2-RDFBasics](SW-2-CSharp-RDFBasics.ipynb) | [Index](README.md) | [4-SPARQL >>](SW-4-CSharp-SPARQL.ipynb)\n", + "" + ] } ], "metadata": { diff --git a/scripts/notebook_tools/twin_pairs.d/sw-3-graph-operations.yaml b/scripts/notebook_tools/twin_pairs.d/sw-3-graph-operations.yaml index dc830900f6..547441e0b2 100644 --- a/scripts/notebook_tools/twin_pairs.d/sw-3-graph-operations.yaml +++ b/scripts/notebook_tools/twin_pairs.d/sw-3-graph-operations.yaml @@ -22,6 +22,13 @@ csharp_sha: d9b84f34b00f68039f500f42cbe354684ee8b8b6 content_python_sha: 5987578811b52065f3590de667a2b537865694536b85274c2105cb21b101ff02 content_csharp_sha: d943d8dd651ab5dc8883560c0cb99ddbcedb445eee60f4ac08a5e206a303a5a6 + - date: "2026-09-03" + by: myia-po-2026:CoursIA + python_sha: 91c69994024084bea93a0823230255624b828ce1 + csharp_sha: b6766929477ff6bc19fc4fb411f8db022504f5ad + content_python_sha: 5987578811b52065f3590de667a2b537865694536b85274c2105cb21b101ff02 + content_csharp_sha: 9a390d7639de119c388942fc2d59d8672318d1666a987541c3b6b77e0df515a7 + reason: "Re-attestation apres PR #14113 (SW-3 C# density enrich #13410) : markdown-only — 4 nouvelles cellules md (31->35), 0 changement de cellule code ; signature sha256 des (source, execution_count, outputs) des 20 cellules code byte-identique base->HEAD (b02bc8424b40c621). Jumeau Python SW-3b non touche (python_sha inchange). parity_level native-both (dotNetRDF/rdflib) intacte — l'enrichissement de prose ne touche ni le code ni les outputs." known_differences: - "Socle commun : parcours de graphe RDF, iteration des triplets, gestionnaires de parsing (handlers)." - "Lib-vs-lib : C# = `dotNetRDF` (`VDS.RDF.Parsing.Handlers`, iterate via `Graph.Triples`). Python = `rdflib` (`rdflib.collection`, `rdflib.parser`, iteration via `graph` set semantics)."