Le langage nomo
Le formalisme nomo repose sur la définition de la base de connaissances et de son moteur d'inférences complété par le moteur de création de règles. Le langage nomo correspond au langage d’expression des règles et des paramètres concernant le moteur d’inférence ainsi que la base de connaissances.
Le langage nomo suit la syntaxe eXtensible Markup Language (XML). Toutefois, l’environnement de développement nomoSDK propose un langage graphique pour définir les règles et leurs relations.
Dans tous les cas, un projet nomo correspond à un document XML appelé unité. Une unité contient trois parties : une partie dédiée au dimensionnement de la base de connaissances, une partie dédiée aux paramètres du moteur d'inférence et une partie dédiée au programme.
Afin de faciliter leur réutilisation, ces différentes parties correspondent à des fichiers XML importés selon la convention XML Inclusions (XInclude).
Après un prétraitement, la validité de la syntaxe et de la cohérence d'une unité est assurée par une grammaire exprimée en XML Schema Definition (XSD), l'ensemble des contraintes évoquées dans la base de connaissances est pris en compte. La pseudo-compilation d'une unité donne un fichier binaire avec l'extension ”.seed” servant à l'initialisation du moteur d'inférence nomoInterpreter.
Dans le langage nomo, les unités et les documents XML inclus possèdent un entête contenant diverses informations pouvant être utilisées pour la génération de la documentation dans l'environnement nomoSDK.
Les noms des différents projets, des types ou des items doivent respecter l'expression régulière suivante : [a-zA-Z]+[a-zA-Z0-9_]*
Les entêtes
Les entêtes des documents XML appartenant au langage nomo possèdent un schéma identique. L'entête donne des informations sur le contexte du projet et sur son contenu. L’internationalisation est permise pour la description des mentions légales et pour le commentaire sur le projet. L'entête est facultatif. Il est représenté par l'élément header qui correspond, s’il existe, au premier fils de la racine du document XML.
Ci-dessous un exemple d'un entête :
<header xmlns="http://www.nomoseed.org/project"> <author> Le nom du programmeur </author> <copyright> <mention xml:lang="fr"> La mention légale et le nom du propriétaire </mention> </copyright> <license name="Le nom de la licence"> <mention xml:lang="fr"> Le contenu ou le résumé de la licence </mention> </license> <datetime> La date du dernier enregistrement </datetime> <version> Le numéro de version </version> <annotation> <documentation xml:lang="fr"> La description du projet </documentation> </annotation> <used_by name="nom du projet utilisant le fichier" location="ici"/> <used_by name="nom d'un autre projet utilisant le fichier" location="là"/> </header>
Les éléments used_by indiquent par quel autre projet celui-ci est utilisé, cette information sert pour la propagation du renommage ou de la suppression dans le cadre de l'environnement nomoSDK et n'a pas d'incidence sur la compilation ou la validation.
Les unités
Une unité est représentée par l'élément nommé unit correspondant à la racine d'un document XML nomo. L'élément unit possède trois attributs :
- l'attribut name indique le nom de l'unité qui sera également le nom, sans l'extension, du fichier binaire résultant de la pseudo-compilation,
- l'attribut binaryLocation indique le chemin du répertoire où sera placé le fichier binaire résultant de la pseudo-compilation,
- l'attribut multiplexer prend les valeurs “yes” ou “no” et indique si l'interfaçage des commandes est multiplexé. Les conséquences sur ce choix sont détaillées dans la présentation du moteur d'inférence nomoInterpreter.
L'élément unit peut contenir un élément header et doit obligatoirement dans l'ordre contenir :
- un élément inference_engine précisant les paramètres du moteur d'inférence ;
- un élément knowledge_base précisant les dimensions de la base de connaissances ;
- un élément program contenant le programme, c'est-à-dire la base de règles initiales.
Ces trois éléments peuvent être inclus via XInclude, comme le montre l'exemple ci-dessous :
<?xml version="1.0" encoding="utf-8"?> <unit name="mon_unite" multiplexer="no" binaryLocation="/ici" xmlns="http://www.nomoseed.org/unit" xmlns:xi="http://www.w3.org/2001/XInclude"> <header xmlns="http://www.nomoseed.org/project"> ... </header> <xi:include href="mon_moteur.eng" parse="xml" /> <xi:include href="ma_base.bas" parse="xml" /> <xi:include href="mon_programme.prg" parse="xml" /> </unit>
L'extension du fichier d'une unité est ”.uni”. Le nom du fichier doit correspondre avec le nom de l'attribut name de la racine.
Le moteur d'inférence
Les paramètres du moteur d'inférence correspondent à ceux contenus dans l'élément inference_engine. L'attribut name de l'élément correspond au nom de la configuration qui doit être le nom du fichier sans l'extension.
L'élément inference_engine peut contenir un entête et doit obligatoirement contenir :
- l'élément frequency indiquant, avec un nombre entier strictement positif, la fréquence (en Hz) des interprétations auquel sera soumis le moteur d'inférence,
- l'élément forget correspondant au seuil de l'oubli d'une règle ; ce seuil est compris entre 0 et 1,
- l'élément check_cover indiquant le coefficient de couverture c qui sera utilisé pour déterminer la durée de l'évaluation d'une prédiction,
- l'élément bid_rate correspondant au taux de l'enchère, le taux est un nombre décimal positif,
- l'élément reimbursement_rate correspondant au taux du remboursement, le taux est un nombre décimal positif,
- l'élément tax_rate correspondant au taux de la taxe, le taux est un nombre décimal positif,
- l'élément reward_rate correspondant au taux de la récompense, le taux est un nombre décimal positif.
L'exemple ci-dessous représente la configuration par défaut avec aucune dynamique :
<inference_engine name="mon_moteur" xmlns="http://www.nomoseed.org/engine" > <header xmlns="http://www.nomoseed.org/project"> ... </header> <frequency value="10"/> <forget value="0.0"/> <check_cover value="1.0"/> <bid_rate value="0.0"/> <reimbursement_rate value="0.0"/> <reward_rate value="0.0"/> <tax_rate value="0.0"/> </inference_engine>
L'extension du fichier des paramètres du moteur d'inférence est ”.eng”.
La base de connaissances
Les dimensions de la base de connaissances sont décrites dans l'élément knowledge_base. L'attribut name de l'élément correspond au nom de la configuration qui doit être le nom du fichier sans l'extension. L'élément knowledge_base contient obligatoirement :
- un élément time_span_limit correspondant à la valeur positive maximale de l'indice temporel d'un évènement dans la mémoire évènementielle, elle s'exprime implicitement en nombre de pas ou en milliseconde en ajoutant 'ms',
- un élément maximum_of_maximizations indiquant le nombre maximal d'ajustements d'une règle, soit un entier positif,
- un élément maximum_of_internal_events correspondant au nombre maximum d'évènements par type contenu dans la mémoire évènementielle. Les types appartiennent à toutes les catégories sauf celles relatives aux entrées. Ce nombre doit être supérieur ou égal à un,
- un élément maximum_of_external_events correspondant au nombre maximum d'évènements par type d'entrée contenu dans la mémoire évènementielle. Ce nombre doit être supérieur ou égal à un,
- un élément maximum_of_rules_by_type correspondant au nombre maximum de règles par type contenu dans la mémoire évènementielle. Ce nombre doit être supérieur ou égal à un,
- un élément maximum_of_premises indiquant le nombre maximal de prémisses d'une règle, soit un entier strictement positif.
Les éléments maximum_of_maximizations, maximum_of_internal_events, maximum_of_rules_by_type, maximum_of_premises contraignent directement le contenu du programme. Toutefois, s’il est souhaité que ce soit le programme qui contraigne ces valeurs, alors la valeur “auto” peut être utilisée pour signifier que la valeur sera déduite automatiquement d'après le contenu du programme.
L'exemple ci-dessous représente la configuration par défaut avec l'utilisation de valeurs automatiques :
<knowledge_base name="ma_base" xmlns="http://www.nomoseed.org/base" > <header xmlns="http://www.nomoseed.org/project"> ... </header> <time_span_limit value="auto"/> <maximum_of_maximizations value="1"/> <maximum_of_internal_events value="auto"/> <maximum_of_external_events value="1"/> <maximum_of_rules_by_type value="auto"/> <maximum_of_premises value="auto"/> </knowledge_base>
L'extension du fichier contenant les dimensions de la base de connaissances est ”.bas”.
Les modèles
Avant d'aborder les programmes, il est nécessaire de présenter les modèles qui seront utilisés dans les programmes.
Un modèle correspond à la définition d'un ensemble de types de connaissance avec leur espace de définition (énumération des items disponibles).
Chaque type du modèle appartient à l’une des douze catégories prédéfinies : entrée (input), commande (command), perception (perception), conception (conception), prédiction (prediction), marque (landmark), opération (operator), désignation (scope), transition (transition), anomalie (anomaly), contrôle (check) et récompense (reward).
Certains types, de par leur catégorie, impliquent nécessairement la présence d’autres types et peuvent introduire des contraintes sur leur ensemble de définitions. Ces interdépendances forment des structures. Certains types ou structures peuvent dépendre de l’existence au préalable d’un autre type ou d’une autre structure.
Un modèle est décrit dans un élément model dont l'attribut name indique son nom ainsi que le nom du fichier sans l'extension. Cet élément peut posséder un entête ainsi qu'une base mais il doit obligatoirement avoir une définition. Ci-dessous une ébauche d'un modèle :
<model name="mon_modele" xmlns="http://www.nomoseed.org/model"> <header xmlns="http://www.nomoseed.org/project"> ... </header> <base> ... </base> <definition> ... </definition> </model>
L'extension d'un fichier contenant un modèle est ”.mod”.
Dans le cadre de l'utilisation de l'environnement nomoSDK, un élément supplémentaire contenant des informations sur la représentation des types peut être rajouté à la fin du document XML de modèle mais cet élément ne fait pas partie du langage nomo en tant que tel.
La base
Un modèle peut être une extension d'un autre modèle servant de base. Dans ce cas, le modèle étendu correspond au modèle de base avec des types supplémentaires ou avec des ensembles de définitions enrichis. L'ajout de relations entre types est également permis, comme l'illustre l'exemple de structure perceptive.
Seul le mécanisme d'extension est autorisé, c'est à dire que la suppression de type ou une restriction des ensembles de définition sont interdites.
L'utilisation du mécanisme d'extension sert à structurer les développements et à valider le respect des dépendances.
Concrètement, l'élément base contient un et un seul modèle à étendre et l'élément definition les nouveaux types ou les types à étendre contenant uniquement les nouveaux items.
<model name="mon_modele_etendu" xmlns="http://www.nomoseed.org/model"> ... <base xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="mon_modele_de_base.mod" parse="xml" /> </base> ... </model>
La définition de types
Selon leur catégories, les types sont définis individuellement ou au sein de structure.
L'élément definition peut contenir des types de commande (élément command_type), des types de conception (élément conception_type), des types de marque (élément landmark_type), des types de récompense (élément reward_type), des structures perceptives (élément perceptive_structure), des structures prédictives (élément predictive_structure) et une unique structure de création de règles (élément plant_structure).
Dans un même modèle, il ne peut y avoir de type ayant le même nom au sein d'une même catégorie.
Avant d'aborder en détail chacun de ces éléments, voici quelques éléments qui leur sont communs.
L'ensemble de définitions des types correspond à une liste d'items contenue dans un élément items. Les éléments item dont le nom correspond à la valeur de l'attribut name. Au sein d'un élément items, le nom de chaque item doit être unique.
Les composantes des vecteurs d'entrée ou de sortie sont définies au sein d'un élément components. Chaque composante se traduit par un élément components dont le nom correspond à la valeur de l'attribut name ; le nom de chaque composante doit être unique. L'ordre des composantes représente leur position dans le vecteur.
Lorsque l'annotation de commentaire est permise, celle-ci prend la forme d'un élément annotation possédant un ou des éléments documentation avec un attribut spécifiant la langue xml:lang et avec pour contenu le commentaire, comme ci-dessous :
<annotation xmlns="http://www.nomoseed.org/project"> <documentation xml:lang="fr"> Un commentaire. </documentation> <documentation xml:lang="en"> A comment. </documentation> </annotation>
Chaque élément iem ou component peut contenir une annotation.
Les types de conception
L'élément conception_type définit un type de conception, l'attribut name indique son nom.
L'élément conception_type contient obligatoirement un élément items. L'élément conception _type peut contenir également :
- un élément annotation,
- un élément rewarded_by dont l'attribut name renvoie au nom du type de récompense défini dans le modèle,
- un élément predicted_by dont l'attribut name renvoie au nom de la structure prédictive définie dans le modèle.
Un type de conception peut être défini à l'intérieur d'un autre type. Dans ce cas, le type de conception ainsi défini correspond à un type jumeau, Son ensemble de définition doit être contenu dans l'ensemble de définition du type qui le définit
Si l'élément conception_type est défini à la racine de l'élément definition, alors il peut contenir également un élément conception_type correspondant à son type jumeau, comme dans l'exemple suivant :
<conception_type name="A"> <rewarded_by name="B" /> <items> <item name="a1" /> <item name="a2"> <annotation> <documentation xml:lang="fr"> Un commentaire. </documentation> </annotation> </item> </items> <conception_type name="AA"> <items> <item name="a1" /> </items> </conception_type> </conception_type>
Les types de commande
L'élément command_type définit un type de commande, l'attribut name indique son nom.
L'élément command_type doit contenir obligatoirement deux éléments :
- un élément items,
- un élément components.
L'élément command_type peut contenir trois autres éléments :
- un élément annotation,
- un élément rewarded_by dont l'attribut name renvoie au nom du type de récompense défini dans le modèle,
- un élément conception_type dont la liste des items doit être contenue dans celle du type de commande.
<command_type name="C"> <rewarded_by name="B" /> <items> <item name="c1" /> <item name="c2" /> </items> <components> <component name="v1" /> <component name="v2" /> <component name="v3" /> </components> </command_type>
Les types de récompense
L'élément reward_type définit un type de récompense, l'attribut name indique son nom.
L'élément reward_type doit contenir obligatoirement un élément items et éventuellement un élément annotation ou un élément conception_type.
Ci-dessous, le type de récompense associé à l'exemple du type de conception ci-dessus :
<reward_type name="B"> <items> <item name="b1" /> </items> </reward_type>
Les types de marque
L'élément landmark_type définit un type de marque, l'attribut name indique son nom. Le nom du type correspond obligatoirement au nom du type de récompense auquel il est associé. Le type de marque définit ici est utilisé indépendamment de toute structure prédictive.
L'élément landmark_type doit contenir obligatoirement un élément items.
L'élément landmark_type peut contenir également :
- un élément annotation,
- un élément rewarded_by dont l'attribut name renvoie au nom du type de récompense défini dans le modèle,
- un élément conception_type.
Ci-dessous, un exemple de définition d'un type de marque :
<landmark_type name="D"> <items> <item name="d1" /> </items> <conception_type name="DD"> <items> <item name="d1" /> </items> </conception_type> </landmark_type>
Les structures prédictives
Une structure prédictive définit trois types associés: un type de prédiction, un type de marque et un type de contrôle. Ces trois types possèdent le même ensemble de définitions. L'attribut name correspond au nom de ces trois types au sein de leur catégorie.
L'élément predictive_structure décrivant cette structure contient obligatoirement un élément items.
L'élément predictive_structure peut contenir également :
- un élément annotation,
- un élément rewarded_by dont l'attribut name renvoi au nom du type de récompense défini dans le modèle,
- un élément conception_type.
Si l'élément rewarded_by est présent, cela signifie que ce sont les trois types de règles qui sont susceptibles d'être rétribués.
Ci-dessous, un exemple de définition d'une structure prédictive minimale dans l'idée d'étendre l’ensemble de définitions lors de la création de règles au cours des interprétations :
<predictive_structure name="E"> <items/> </predictive_structure>
Les structures perceptives
Une structure perceptive définit deux types associés : un type d'entrée et un type de perception.
L’élément perceptive_structure décrivant cette structure contient obligatoirement :
- Un élément items qui correspond à l'ensemble de définitions du type de perception. Un type d'entrée ne possède pas d'ensemble de définitions. Les vecteurs d'entrée étant des valeurs continues, ce sont les prémisses des règles de perception qui caractérisent en quelque sorte l'ensemble de définitions.
- Un élément components correspond aux composantes du vecteur d'entrée.
L'élément predictive_structure peut contenir également :
- un élément annotation,
- un élément rewarded_by dont l'attribut name renvoie au nom du type de récompense défini dans le modèle,
- un élément predicted_by dont l'attribut name renvoie au nom de la structure prédictive définie dans le modèle,
- un élément conception_type,
- un élément command_type correspondant à la définition d'un type de commande lié à cette structure perceptive. L'ensemble de définitions du type de commande doit être inclus dans celle du type de perception. L'élément command_type n'a dans ce cas pas d’élément components puisque celui-ci correspond à celui du type d'entrée. Le type de commande possède le même nom que la structure perceptive, par conséquent ; il ne possède pas d'attribut name.
Ci-dessous un exemple de structure perceptive avec un type de commande lié :
<predictive_structure name="F"> <items> <item name="f1" /> <item name="f2" /> </items> <components> <component name="v1" /> <component name="v2" /> </components> <command_type> <items> <item name="f2" /> </items> </command_type> </predictive_structure>
La structure de création de règles
Une structure de création de règles dans un modèle correspond à l'extension d'une structure de création de règles prédéfinies qui déclare les types et leurs ensembles de définition de base imposés par le moteur de création de règles.
La structure de création de règles prédéfinie déclare six types avec leur ensemble de définitions.
Le type transition
Le type transition (nommé en langage nomo transition) correspond au seul et unique type de la catégorie de connaissance relative aux transitions. Son ensemble de définitions correspond aux quatre transitions d'états du moteur de création de règles permises directement par des événements :
- la transition vers l'état « Affectation » nommée begin_affectation,
- la transition vers l'état « Inhibition » nommée begin_inhibition,
- la transition vers l'état « Excitation » nommée begin_excitation,
- la transition vers l'état « Finalisation » nommée begin_finalization.
Cet ensemble de définitions ne peut être étendu dans un modèle.
Les types dédiés au registre des entrées
L'utilisation d'un registre s'appuie sur deux types, l'un appartenant à la catégorie de connaissances relatives aux opérateurs et l'autre appartenant à la catégorie de connaissances relatives aux désignations. Pour le registre dédié aux entrées, cette paire de types dans le langage nom est nommé register_00.
Le type register_00 de la catégorie relative aux opérateurs (operator) a pour ensemble de définitions les opérateurs d'affectation, soit les opérateurs suivant :
- « prendre celui-là » nommé get_there,
- « prendre le début » nommé get_first,
- « prendre le précédent » nommé get_before,
- « prendre le dernier » nommé get_last.
- « prendre le suivant » nommé get_after.
Les opérateurs « créer une prémisse » spécifiant la tolérance que les informations de la prémisse d'entrée à créée, sont aussi à rajouter dans le cadre d'une extension. L'élément item définissant un de ces opérateurs « créer une prémisse» contient un élément premisse contenant à son tour l'élément information dont l'attribut tolerance correspond à la tolérance initiale des informations.
<input> <operator_type> <item name="create_premise_1"> <premise> <informations tolerance="0.1"/> </premise> </item> ...
Le type register_00 de la catégorie relative aux désignations (scope) a pour ensemble de définitions les items correspondant aux types autorisés à être référencés. Ces items contiennent un élément target possédant un triplet d'attribut spécifiant la catégorie (category), le modèle (model), et le nom du type (type). Dans le cas du register_00, la valeur de l'attribut de la catégorie se trouve fixée à input, la valeur du modèle peut prendre soit la valeur this désignant le modèle dans lequel il est définit, soit la valeur * désignant l'ensemble des modèles du programmes mais pas ceux des sous-programmes sauf s'ils sont importés.
A l'édition des liens du programme, toute une désignation doit porter sur au moins un type.
Les types dédiés aux autres registres
Le nombre des autres registres définis dans l'extension détermine le nombre de paires de types dédiés aux autres registres, chaque paire de types a le même nom register_, suivi du numéro du registre précédé d'un zéro si inférieur à dix. Le nombre des autres registres égal ou supérieur à un, par conséquent la paire de types register_01 est toujours défini. Tous les types de même catégorie dédiée aux autres registres que le registre d'entrée ont le même ensemble définitions.
Les types de la catégorie relative aux opérateurs (operator) ont pour ensemble de définitions les opérateurs d'affectation, soit les opérateurs suivant :
- « prendre celui-là » nommé get_there,
- « prendre le début » nommé get_first,
- « prendre le précédent » nommé get_before,
- « prendre le dernier » nommé get_last,
- « prendre le suivant » nommé get_after,
- « prendre le même » nommé get_same,
- « cibler celui-là » nommé target,
- « copier » nommé copy,
- « créer un concept » nommé create_conception,
- « créer une récompense » nommé create_reward,
- « créer une marque» nommé create_landmark,
- « créer une commande » nommé create_command,
- « créer un concept jumeau » nommé create_twin,
- « créer une perception décalée» nommé create_perception_forward,
- « créer une prédiction » nommé create_prediction,
- « créer un contrôle décalé » nommé create_check_forward.
Les opérateurs liés au repère temporel :
- « transformer en repère temporel » nommé transform_in_temporal_reference,
- « transformer en repère et origine temporel » nommé transform_in_temporal_reference_and_origin.
Et les opérateurs liés à la manipulation des indices temporels :
- « s'aligner sur » nommé same_time
- « avancer » nommé forward
- « reculer » nommé backward
Les éléments item qui servent à définir les opérateur « créer une prémisse » contiennent un élément premise pouvant avoir comme triplet d'attributs type, model et category.
Ce triplet d'attribut s'impose lorsque l'information est précisée ou lorsque l'indice temporel spécifié est négatif. En dehors, de ces cas il n'est pas nécessaire de spécifié le type car si l'information n'est pas spécifié ce sera l'information de l'item qui sera utilisée et dans ce cas une vérification du type sera effectué entrainant une anomalie si incohérence.
L'élément premise doit contenir obligatoirement les trois éléments suivant information, credibility et timespan avec pour attribut tolerance et éventuellement l'attribut value sous réserve de sa cohérence avec le type lors de l'édition des liens du programme. Naturellement, la tolérance pour l'information ne peut être que infinie ou nulle. Par exemple :
<other> <operator_type> <item name="create_premise"> <premise> <information tolerance="0"/> <credibility tolerance="INF"/> <timespan tolerance="0"/> </premise> </item> ...
Les éléments item, qui servent à définir les opérateur « créer une conclusion», contiennent un élément conclusion avec obligatoirement deux attributs qui renvoient aux valeurs initiales d'une règle : l'espérance (nommée relevance) et le nombre d'ajustements (nommé fitting_nbr). Le nombre d'ajustements sert à donner, si c'est souhaité, une certaine inertie à l'adaptation de la nouvelle règle, en considérant qu'elle résulte d'une moyenne effectuée sur une valeur fois le nombre d'ajustement plus un.
L'élément conclusion peut contenir l'élément information avec l'attribut value, l'élément delay avec l'attribut value ou l'élément target avec le triplet d'attributs type, model et category. L'élément target s'impose uniquement lorsque l'information est précisée ou lorsque le délai est spécifié et non nul. En dehors, de ces cas il n'est pas nécessaire de spécifié le type car si l'information n'est pas spécifié ce sera l'information de l'item qui sera utilisée et dans ce cas une vérification du type sera effectué entrainant une anomalie si incohérence.
Les types de la catégorie relative aux désignations (scope) suivent également le même schéma que pour le registre d'entrée, hormis le fait que la catégorie puisse prendre une liste toutes les valeurs sauf input, soit : la perception (perception), la conception (conception), la commande (command), la prédiction (prediction), le marquage (landmark), le contrôle (check), la récompense (reward), la transition (transition), l'opération (operator, la désignation (scope), l'anomalie (anomaly), soit * désignant l'ensemble des catégories possibles. L'attribut model peut prendre soit la valeur this, soit la valeur plant, soit les deux, soit * désignant tous les modèles du programme hormis ceux des sous-programmes non-importés. La valeur plant désigne le modèle de la structure de création de règles prédéfinie.
Le type anomalie
Le type anomalie (nommé en langage nomo anomaly) correspond au seul et unique type de la catégorie relative aux anomalies. L'ensemble de définition, qui ne peut être étendu dans un modèle, correspond dans l'ordre à : …
La description de l'extension de la structure de création de règles se traduit alors par un élément plant_structure ayant pour attribut others_register indiquant le nombre des registres autres que le registre s'occupant des entrées. Cet élément contient obligatoirement deux autres éléments décrivant réciproquement les types dédiés au registre d'entrée input et ceux d'un registre prototypique dédié aux autres types d'évènements other. Ces deux éléments contiennent deux éléments correspondant réciproquement aux extensions des ensembles de définition des opérateurs et des désignations.
L'extension de la structure de création de règles peut contenir un élément reward_by qui indique le type de récompense associé pour tous les types définis.
Ci-dessous un exemple d'une extension de la structure de création de règle :
<plant_structure others_registers_nbr="5"> <input> <operator_type> <item name="create_premise_1"> <premise> <informations tolerance="0.1" /> </premise> </item> <item name="create_premise_2"> <informations tolerance="3.0" /> </premise> </item> </operator_type> <scope_type> <item name="s1"> <target category="input" model="this" type="motor" /> </item> </scope_type> </input> <other> <operator_type> <item name="create_premise_1"> <premise> <information tolerance="0"/> <credibility tolerance="0"/> <timespan tolerance="5"/> </premise> </item> <item name="create_conclusion_1"> <conclusion relevance="0.5" fitting_nbr="2"/> </item> <item name="create_conclusion_2" > <conclusion relevance="1.0" fitting_nbr="INF"> <delay value="0"/> </conclusion> </item> </operator_type> <scope_type> <item name="s1"> <target category="perception" model="*" type="*"/> </item> </scope_type> </other> </plant_structure>
La validité de l'ensemble des attributs est effectuée totalement uniquement à l'édition des liens de l'unité utilisant une instance du modèle contenant un élément plant_structure.
La liste des anomalies que peut généré le moteur de création de règles en cas de mauvais utilisation :
AFFECTATION_EXPIRED_FOR_REFERENCE_TIME | ILLEGAL_OPERATOR_IN_CONDITION |
AFFECTATION_EXPIRED_FOR_SHIFTING_TIME | ILLEGAL_REFERENCE_FOR_CREATION |
AFFECTATION_EXPIRED_OPERATOR_FOR_TARGET | ILLEGAL_REFERENCE_FOR_INPUT_CONDITION |
ALREADY_AFFECTED_CHUNK | ILLEGAL_REFERENCE_FOR_INTERNAL_CONCLUSION |
ALREADY_CREATED_PERCEPTION | ILLEGAL_REFERENCE_FOR_INTERNAL_CONDITION |
ALREADY_DESIGNED_REFERENCE_TIME | ILLEGAL_REFERENCE_FOR_PERCEPTION_CONCLUSION |
ALREADY_DESIGNED_TARGET | ILLEGAL_START_IN_AFFECTATION |
BAD_REFERENCE_TIME | ILLEGAL_START_IN_CONCLUSION |
EXPIRED_EXTERNAL_CHUNCK | ILLEGAL_START_IN_EXCITATORY_PREMISE |
EXPIRED_INTERNAL_CHUNCK | ILLEGAL_START_IN_INHIBITORY_PREMISE |
EXPIRED_INTERNAL_TARGET | ILLEGAL_START_IN_STANDBY |
FAIL_CHUNCK_INACTIVE | ILLEGAL_TARGET_IN_EXTERNAL_CHUNK |
FAIL_LANDMARK_ID | INPUT_PREMISE_IN_INHIBITORY_PREMISE |
FAIL_LANDMARK_TYPE | INPUT_PREMISE_MISSING |
FAIL_LINKED_PERCEPTION | MISSING_LANDMARK_RULE |
FAIL_PERCEPTION_OF_COMMAND_CONCLUSION | MISSING_PREDICTIVE_RULE |
FAIL_PREDICTION_ID_IN_CHECKING_RULE | MISSING_TARGET_FOR_AFFECTATION_OPERATOR |
FAIL_PREDICTIVE_TYPE_IN_CHECKING_RULE | NO_UNIQUE_COMMAND_CONCLUSION |
FAIL_SEARCH_EVENT | NO_UNIQUE_PERCEPTION_CONCLUSION |
FAIL_TARGETED_AFFECTATION | NO_UNIQUE_PREDICTION_CONCLUSION |
FORBIDDEN_REFLECTION_RETURN_IN_CONCLUSION | OVER_AFFECTATION_OPERATORS_FOR_TARGET |
ILLEGAL_CREATION_OPERATOR_IN_EXTERNAL_CHUNK | OVER_INPUT_PREMISE |
ILLEGAL_CREATION_OPERATOR_IN_INTERNAL_CHUNK | OVER_INTERNAL_PREMISES_NUMBER |
ILLEGAL_LANDMARK_TYPE | OVER_RULES |
ILLEGAL_OPERATOR_IN_AFFECTATION | OVER_TIME_SPAN_FOR_INTERNAL_CONDITION |
ILLEGAL_OPERATOR_IN_CONCLUSION | SAME_TIME_CONDITION_CONCLUSION |
Un programme est décrit par l'élément program. L'attribut name de l'élément correspond au nom de la configuration qui doit étre le nom du fichier sans l'extension. L'élément program contient directement deux éléments :
- l'élément subprograms listant les programmes inclus dans le programme principal,
- l'élément body correspondant au corps du programme qui contient à la fois les règles et leurs modèles.
Un programme doit contenir au minimum soit un élément subprograms, soit un élément body.
Ci-dessous l'exemple d'une ébauche de programme :
<program name="mon_programme" xmlns="http://www.nomoseed.org/program" > <header xmlns="http://www.nomoseed.org/project"> ... </header> <subprograms> ... </subprograms> <body> ... </body> </programs>
L'extension du fichier d'un programme est ”.prg”.
Dans le cadre de l'utilisation de l'environnement nomoSDK, un élément supplémentaire contenant des informations sur la représentation et sur la validation des règles peut être rajouté à la fin du document XML de programme mais cet élément ne fait pas partie du langage nomo en tant que tel.
Les sous-programmes
En dehors du programme principal, les autres programmes sont considérés comme des prototypes de programme qu'il est possible d'instancier comme sous-programme.
L'instanciation correspond à l'insertion d'une copie d'un programme dont les noms des règles et des types seront renommés en fonction du nom de l'instance.
Plusieurs sous-programmes peuvent être l'instance d'un même programme et peuvent être interprétés indépendamment les uns des autres.
Le programme instancié est contenu dans l'élément new dont l'attribut instance correspond au nom de l'instance. Deux instances du même programme ne peuvent avoir le même nom lors de la pseudo-compilation.
Afin de contrôler la création des instances, il est possible de créer une nouvelle instance uniquement si aucune autre instance n’existe dans un programme parent. Dans ce cas, le programme susceptible d'être instancié est contenu dans l'élément inherite dont l'attribut instance correspond au nom de l'instance.
Dans l'exemple ci-dessous, deux sous-programmes représentent deux agents différents définis par le programme prototype “agent”. Le sous-programme “mon_alarme” correspond à l'instance du programme “alarme” dans le cas où “mon_programme” est le programme principal.
<program name="mon_programme" xmlns="http://www.nomoseed.org/program"> <subprograms xmlns:xi="http://www.w3.org/2001/XInclude"> <new instance="agent_1"> <xi:include href="agent.prg" parse="xml" /> </new> <new instance="agent_2"> <xi:include href="agent.prg" parse="xml" /> </new> <inherite instance="mon_alarme"> <xi:include href="alarme.prg" parse="xml" /> </inherite> </subprograms> ... </program>
Si le programme “agent” déclare un nouveau sous-programme (élément new) nommé “mon_alarme” alors, il sera considéré comme étant un sous-programme distinct du sous-programme “mon_alarme” du programme parent.
Si le programme “agent” déclare un sous-programme hérité (élément inherite) nommé “autre_alarme” alors, il sera considéré comme étant un sous-programme distinct du sous-programme “mon_alarme” du programme parent.
Si le programme “agent” déclare un sous-programme hérité (élément inherite) nommé “mon_alarme” alors, il sera considéré comme étant le sous-programme “mon_alarme” du programme parent.
Au sein d'un élément subprograms, toutes les instances doivent posséder un nom unique.
Un exemple d'utilisation de ces différentes manières d'instancier se trouve dans la troisième partie du tutoriel.
Le corps du programme
Le corps d'un programme est composé de deux éléments. Le premier élément, nommé models, contient tous les modèles utilisés par le programme et le second , nommé scheme, contient le schème global. Un schème représente un ensemble de règles et de schèmes.
<program name="mon_programme" xmlns="http://www.nomoseed.org/program"> ... <body> <models> ... </models> <scheme> ... </scheme> </body> </program>
Pour tous les éléments du corps une annotation est permise.
Les modèles
De la même manière que pour les sous-programmes, il faut instancier les modèles. L'instanciation a pour effet de recopier le modèle et de modifier le nom des types en fonction de l'instance. Il est donc possible d'avoir deux instances du même modèle sans confusion aucune entre les types.
Il existe trois manières différentes d'instancier un modèle : soit en déclarant obligatoirement une nouvelle instance, soit par héritage, soit par importation. Ces trois manières d'instancier se traduisent par un élément particulier avec pour attribut instance le nom de l'instance contenant le modèle à instancier. Par ailleurs, chacun de ces éléments doit contenir le prototype de modèle à instancier :
- La première manière d'instancier s'effectue directement par l’intermédiaire d'un élément new.
- L’instanciation par héritage est indiquée par l'élément inherite. Dans ce cas, si aucune autre instance dans un programme parent de même nom existe et qu'il contient le modèle désigné, alors une nouvelle instance est créée, sinon l'instance considérée sera l'instance préexistante du programme parent. Soit le modèle M1 et le modèle M2 ayant pour base M1, si leur nom d'instance concorde, M1 peut hériter de M2 mais M2 ne peut être hérité à partir de M1. Par ailleurs, un modèle ne peut pas hériter d'une nouvelle instance frère ni d'un modèle importé.
- La dernière manière d'instancier un modèle correspond à importer une instance d'un modèle appartenant à un sous-programme via l'élément import. L'attribut subprogram permet de d'indiquer le sous-programme visé et l'attribut instance indique le nom de l'instance du modèle dans le sous-programme et qui doit être repris dans le programme parent.
Un élément models contient obligatoirement au moins une instance.
Au sein d'un élément models tous les noms des instances de modèles doivent être différents. L'exemple suivant illustre les trois instanciations possibles :
<models xmlns:xi="http://www.w3.org/2001/XInclude"> <new instance="modele_1"> <xi:include href="mon_modele.mod" /> </new> <inherite instance="modele_2"> <xi:include href="mon_modele.mod" /> </inherite> <import instance="modele_3" subprogram="mon_sous_programme"> <xi:include href="mon_modele.mod" /> </import> </models>
Dans le cas où le modèle a été définit au sein du programme, le chemin du modèle est indiqué à l'aide de la norme XPointer comme suit :
<import instance="modele_3" subprogram="mon_sous_programme"> <xi:include href="mon_program.prg# xmlns(model=http://www.nomoseed.org/model) xpointer((//model:model[@name='mon_modele'])[1])"/> </import>
Un exemple d'utilisation de ces différentes manières d'instancier se trouve dans la troisième partie du tutoriel.
Les schèmes et les règles
Un schème représente un ensemble de règles et de schèmes. Un schème est représenté par un élément scheme dont le nom est indiqué par l'attribut name. Le schème global contient tous les schèmes et non celui correspondant au nom du programme, de sorte qu'il ne possède pas l'attribut name.
Les règles contenues dans les schèmes sont décrites par l'élément rule qui possède trois attributs :
- le nom de la régle (name),
- la pertinence (relevance),
- le nombre d'ajustements (fitting_nbr), lorsqu'il n'est pas souhaité d'effectuer de nouveaux ajustements, il est considéré infini et prend la valeur “INF”.
Si l’attribut relevance est omis alors il sera considéré à 1. Si l’attribut fitting_nbr est omis alors il sera considéré valant “INF”.
Une règle contient éventuellement des prémisses mais contient obligatoirement une conclusion. Une prémisse est représentée par l'élément premise possédant trois attributs :
- le type visé par la prémisse (type),
- l'instance du modèle définissant le type (model),
- la catégorie du type (category).
Si la prémisse vise un évènement relatif à une entrée, alors la prémisse contient autant d'éléments information que de composantes définies par le type associé. L'ordre de ces éléments doit correspondre à l'ordre défini par le type associé. Chaque élément information possède dans ce cas deux attributs :
- la valeur de la composante (value),
- la tolérance associée à cette valeur (tolerance).
Si la prémisse vise un type d'événement autre qu'un événement relatif à une entrée, alors la prémisse contient trois éléments représentant l'information (information), la crédibilité (credibility) et l'indice temporel (timespan). Chacun de ces éléments possède deux attributs relatifs à leur valeur (value) et à leur tolérance (tolerance). Si la prémisse est inhibitrice, l'attribut inhibitor à la valeur “true” doit être ajouté à l'élément premise. Par ailleurs, si la crédibilité et l'indice temporel sont omis alors ils auront respectivement pour les couples (valeur,tolérance) suivant (1,INF) et (0,INF).
Pour l'indice temporel (timespan) s'exprime soit en milliseconde auquel cas il faut rajouter 'ms' après la valeur, soit en nombre de pas. Deux constantes peuvent être également utilisé 'MIN' et 'MAX' représentant réciproquement les bornes inférieur et supérieur de la mémoire. 'MIN' représente le nombre maximum de pas de retard pour une intention et 'MAX' représente le nombre maximum de pas inférieur à time_span_limit. Il est possible d'ajouter des pas ou des millisecondes à 'MIN', de même il est possible de retrancher à 'MAX' des pas ou des millisecondes tant que le résultat est supérieur à zéro.
Plus précisément,dans la version 2013 du moteur nomoInterpreter, le 'MIN' en terme de pas se calcule en arrondissant à l'inférieur comme suit :
Par ailleurs, la tolérance associée à l'indice temporel (timespan) peut être exprimée en fonction du pas temporel en ajoutant le mot clé 'period' ou 'periods'.
Dans une prémisse, si un élément possède un attribut tolerance à “INF”, il n'est alors pas nécessaire d'avoir l'attribut value. Sauf pour l'indice temporel où l'attribut doit être renseigné pour indiquer le signe déterminant s’il s'agit d'une intention.
Une conclusion est représentée par l'élément conclusion avec trois attributs :
- le type de la conclusion (type),
- l'instance du modèle définissant le type (model),
- la catégorie du type (category)
L'élément conclusion contient un élément information avec un attribut value donnant la valeur de la conclusion.
Si la conclusion est une prédiction ou une conception avec un délai alors un attribut indiquant le délai (delay) doit être rajouté. Ce délai peut correspondre soit un simple nombre naturel représentant un nombre de pas, soit un nombre naturel suivis de 'ms' signifiant qu'il s'agit de millisecondes, soit 'MAX' représentant le nombre de pas maximales pour un délais. Il possible de retrancher à la valeur 'MAX' soit un nombre de pas soit un nombre de milliseconde, par exemple : 'MAX - 10ms'.
Plus précisément,dans la version 2013 du moteur nomoInterpreter, le 'MAX' en terme de pas se calcule en arrondissant à l'inférieur comme suit :
À noter, la constante 'MAX' pouvant être utilisée pour l'attribut delay correspond à la constante 'MIN' de pouvant être utilisée pour la valeur de timespan avec un signe opposé.
Si la conclusion est une commande, alors l'élément contient autant d'éléments output que de composantes définies par le type associé. L'ordre de ces éléments doit correspondre à l'ordre défini par le type associé. Chaque élément output possède un attribut value indiquant la valeur de la composante.
Dans le cas des prémisses ou des conclusions appartenant à la catégorie des opérateurs ou des désignations, l'attribut value (de l’élément information) est remplacé par les attributs nécessaires à la description de l'item évoqué. Par exemple, pour une prémisse visant une désignation, l'information possède à la place de value : target_category, target_model et target_type.
Ci-dessous un exemple d'un schème global rappelant les différentes configurations en dehors de règles liées aux catégories relatives aux opérations et aux désignations. La règle “start” se déclenche à la première interprétation puis est éliminée car elle a une espérance nulle. Son déclenchement produit une intention à durée infinie qui sera supprimée au déclenchement de la règle “end”. Ce dernier sera déclenché lorsque la commande “alert” sera envoyée au déclenchement de la règle “action”. La règle “action” se déclenchera à l'arrivée d'une perception “perception_1” et s’il y a une intention “start” et s'il n'y a pas eu de commande à la dernière interprétation. La règle de détection se déclenchera lorsque un évènement approprié arrivera et si l'intention “start” est présente dans la base de faits.
<scheme> <rule name="start" relevance="0" fitting_nbr="INF"> <conclusion category="conception" model="modele_1" type="interrupteur"> <information value="start" delay="MAX" /> </conclusion> </rule> <rule name="end"> <premise category="command" model="modele_1" type="ma_command"> <information tolerance="INF" /> <credibility tolerance="INF" /> <timespan value="0" tolerance="0" /> <premise> <conclusion category="conception" model="modele_1" type="interrupteur"> <information value="end" /> </conclusion> </rule> <scheme name="mon_scheme_1"> <rule name="detection"> <premise category="input" model="modele_1" type="mon_entree"> <information value="1.0" tolerance="2.0" /> <information value="2.5" tolerance="1.5" /> <premise> <premise category="conception" model="modele_1" type="perception_1"> <information value="start" tolerance="0" /> <credibility tolerance="INF" /> <timespan value="-1.0" tolerance="INF" /> <premise> <conclusion category="perception" model="modele_1" type="mon_entree"> <information value="perception_1" /> </conclusion> </rule> <rule name="action"> <premise category="perception" model="modele_1" type="perception_1"> <information value="perception_1" tolerance="0" /> <credibility tolerance="INF" /> <timespan value="0" tolerance="0" /> <premise> <premise category="command" model="modele_1" type="ma_command" inhibitor="true"> <information tolerance="INF" /> <credibility tolerance="INF" /> <timespan value="0" tolerance="0" /> <premise> <conclusion category="command" model="modele_1" type="mon_entree"> <information value="alert" /> <output value="1.0" /> </conclusion> </rule> </scheme> </scheme>
Dans le tutoriel se trouvent de nombreux exemples de programme.