Comment gérer des milliers de règles IF… THEN… ELSE?


214

J'envisage de créer une application qui, à la base, consisterait en des milliers de déclarations si… alors… autres. Le but de l'application est de pouvoir prédire comment les vaches se déplacent dans n'importe quel paysage. Ils sont affectés par des facteurs comme le soleil, le vent, les sources de nourriture, les événements soudains, etc.

Comment gérer une telle application? J'imagine qu'après quelques centaines d'instructions IF, il serait presque imprévisible que le programme réagisse et que le débogage conduisant à une certaine réaction signifie qu'il faille traverser tout l'arborescence des instructions IF à chaque fois.

J'ai lu un peu sur les moteurs de règles, mais je ne vois pas comment ils contourneraient cette complexité.


22
Vous devez jeter un coup d'œil à la programmation DSL: en.wikipedia.org/wiki/Domain-specific_language Vous pouvez également éventuellement créer un moteur de règles méta pilotées par les données. Par exemple, vous pouvez générer des modèles à partir de données (par exemple, l'extraction de données KDD)
Darknight

14
google pour "système expert" et "rete net"; bonne chance.
Steven A. Lowe

9
Déplacez les instructions if / then codées en dur du code source vers des données externes qui pilotent la simulation.
Kwebble

6
Je bongais quelques valeurs dans un fichier texte et utilisais une boucle pour parcourir un HashMap contenant des noms.
James P.

2
Les questions de David - on Programmers sont converties en CW lorsque plus de 15 réponses sont postées. Nous ne pouvons pas contrôler qui publie la 16ème réponse.
ChrisF

Réponses:


73

Le langage de programmation logique Prolog est peut-être ce que vous recherchez. Votre énoncé de problème n’est pas assez précis pour que je puisse déterminer s’il s’agit bien, mais c’est assez semblable à ce que vous dites.

Un programme Prolog est constitué de faits et de règles appliqués. Voici un exemple de règle simple qui indique "Une vache se déplace vers un endroit si elle a faim et qu'il y a plus de nourriture dans le nouvel emplacement que dans l'ancien endroit":

moves_to(Cow, Location) :-
  hungry(Cow),
  current_location(Cow, OldLoc),
  food_in(OldLoc, OldFood), food_in(Location, NewFood),
  NewFood > OldFood.

Toutes les choses en majuscules sont des variables, des choses dont vous ne connaissez pas la valeur. Prolog tente de trouver des valeurs pour ces variables qui remplissent toutes les conditions. Ce processus est effectué avec un algorithme puissant appelé unification, qui est au cœur de Prolog et d’environnements de programmation logique similaires.

En plus des règles, une base de données de faits est fournie. Un exemple simple qui fonctionne avec les règles ci-dessus pourrait être quelque chose comme:

current_location(white_cow, pasture).

current_location(black_cow, barn).
hungry(black_cow).

current_location(angry_bull, forest).
hungry(angry_bull).

food_in(barn, 3).
food_in(pasture, 5).
food_in(forest, 1).

Notez que white_cow et pasture, etc. ne sont pas écrits en majuscules. Ce ne sont pas des variables, ce sont des atomes.

Enfin, vous posez une question et demandez ce qui va se passer.

?- moves_to(white_cow, Destination).
No.
?- moves_to(black_cow, Destination).
Destination = pasture
?- moves_to(Cow, Destination).
Cow = black_cow, Destination = pasture
Cow = angry_bull, Destination = barn
Cow = angry_bull, Destination = pasture

La première requête demande où la vache blanche va se déplacer. Compte tenu des règles et des faits ci-dessus, la réponse est non. Cela peut être interprété comme "je ne sais pas" ou "ça ne bouge pas" selon ce que vous voulez.

La deuxième requête demande où la vache noire se déplace. Il se déplace au pâturage pour manger.

La dernière requête demande où toutes les vaches sont déplacées. En conséquence, vous obtenez tout ce qui est logique (vache, destination). Dans ce cas, le taureau noir se déplace au pâturage comme prévu. Cependant, le taureau énervé a deux choix qui satisfont aux règles, il peut soit se déplacer au pâturage ou à la grange.

Note: Cela fait des années que j'ai écrit Prolog pour la dernière fois, tous les exemples ne sont peut-être pas syntaxiquement corrects, mais l'idée devrait être correcte.


10
-1: Je ne pense pas que Prolog puisse être la bonne réponse. Oui, il pourrait être facile d’obtenir des règles if-else dans Prolog. Mais vous devrez certainement faire autre chose. Et peu importe ce que c'est (IO; interface graphique, développement Web, ...), ce sera un problème avec Prolog.
Martin Thoma

4
Découvrez learnprolognow.com Et intégrer le prologue dans une autre langue est beaucoup plus facile qu'auparavant
Zachary K

@ZacharyK: Le lien est brisé.
RenniePet

@ MartinThoma: pouvez-vous expliquer votre commentaire? Les principaux problèmes de Prolog IMHO sont l’absence 1. de moyen déclaratif de contrôler la recherche et la 2. saisie. Mais si votre application ne dépend pas beaucoup de ces deux logiciels, je ne vois pas a priori de problème pour utiliser Prolog ici
SN

139

Pour résoudre le problème if web , vous pouvez créer un moteur de règles dans lequel chaque règle spécifique est codée indépendamment. Un raffinement supplémentaire dans ce sens consisterait à créer un langage spécifique au domaine (DSL) pour créer les règles. Toutefois, un DSL seul déplace uniquement le problème d’une base de code (principale) à une autre (DSL). Sans structure, la DSL ne sera pas mieux lotie que le langage natif (Java, C #, etc.), nous y reviendrons dès que nous aurons trouvé une approche structurelle améliorée.

Le problème fondamental est que vous rencontrez un problème de modélisation. Chaque fois que vous rencontrez des situations combinatoires comme celle-ci, cela indique clairement que votre abstraction de modèle décrivant la situation est trop grossière. Vous combinez probablement des éléments qui doivent appartenir à différents modèles dans une même entité.

Si vous continuez à décomposer votre modèle, vous finirez par dissoudre complètement cet effet combinatoire. Cependant, lorsque vous empruntez ce chemin, il est facile de vous perdre dans votre conception, créant ainsi un désordre encore plus grand. Le perfectionnisme n’est pas nécessairement votre ami.

Les machines à états finis et les moteurs de règles ne sont qu'un exemple de la manière dont ce problème peut être décomposé et rendu plus gérable. L'idée principale ici est qu'un bon moyen d'éliminer un problème combinatoire tel que celui-ci est souvent de créer un dessin et de le répéter ad-nauseam à des niveaux d'abstraction imbriqués jusqu'à ce que votre système fonctionne de manière satisfaisante. Semblable à la façon dont les fractales sont utilisées pour créer des motifs complexes. Les règles restent les mêmes, que vous regardiez votre système avec un microscope ou avec une vue à vol d'oiseau.

Exemple d'application de ceci à votre domaine.

Vous essayez de modéliser la façon dont les vaches se déplacent sur un terrain. Bien que votre question manque de détails, je suppose que votre grande quantité de ifs inclut un fragment de décision tel que, if cow.isStanding then cow.canRun = truemais vous vous perdez à mesure que vous ajoutez des détails de terrain, par exemple. Donc, pour chaque action que vous souhaitez entreprendre, vous devez vérifier tous les aspects auxquels vous pouvez penser et répéter ces vérifications pour la prochaine action possible.

Nous avons d’abord besoin de notre conception répétable, qui dans ce cas sera un FSM pour modéliser les états changeants de la simulation. La première chose à faire est donc de mettre en œuvre un FSM de référence, en définissant une interface d' état , une interface de transition et peut-être un contexte de transition.qui peut contenir des informations partagées à mettre à la disposition des deux autres. Une implémentation FSM de base bascule d'une transition à une autre, quel que soit le contexte. C'est ici qu'un moteur de règles entre en jeu. Le moteur de règles résume proprement les conditions à remplir pour que la transition se produise. Un moteur de règles peut être aussi simple qu'une liste de règles, chacune ayant une fonction d'évaluation retournant un booléen. Pour vérifier si une transition doit se produire, nous parcourons la liste des règles et, si l'une d'entre elles est évaluée comme étant fausse, la transition n'a pas lieu. La transition elle-même contiendra le code de comportement permettant de modifier l'état actuel du FSM (et d'autres tâches possibles).

Maintenant, si je commence à implémenter la simulation en tant que grand FSM unique au niveau de DIEU, je me retrouve avec BEAUCOUP d'états possibles, de transitions, etc. Maintenant, une règle effectue un test sur une information spécifique du contexte (qui contient à peu près tout le contenu) et chaque corps IF se trouve quelque part dans le code de transition.

Entrez la répartition des fractales: la première étape serait de créer un FSM pour chaque vache dans lequel les états sont les états internes de la vache (debout, courir, marcher, pâturage, etc.) et les transitions entre eux seraient influencés par l'environnement. Il est possible que le graphique ne soit pas complet. Par exemple, le pâturage n'est accessible qu'à partir de l'état permanent. Toute autre transition est dissoute car simplement absente du modèle. Ici, vous séparez efficacement les données dans deux modèles différents, la vache et le terrain. Chacun avec son propre ensemble de propriétés. Cette répartition vous permettra de simplifier la conception globale de votre moteur. Désormais, au lieu d’avoir un seul moteur de règles qui décide tout, vous disposez de plusieurs moteurs de règles plus simples (un pour chaque transition) qui déterminent des détails très spécifiques.

Comme je réutilise le même code pour le FSM, il s’agit essentiellement d’une configuration du FSM. Rappelez-vous quand nous avons mentionné plus tôt DSL? C’est là que le DSL peut faire beaucoup de bien si vous avez beaucoup de règles et de transitions à écrire.

Aller plus loin

Maintenant, DIEU n'a plus à gérer toute la complexité de la gestion des états internes de la vache, mais nous pouvons aller plus loin. La gestion du terrain, par exemple, reste complexe. C'est ici que vous décidez où la ventilation est suffisante. Si, par exemple, dans votre DIEU vous finissez par gérer la dynamique du terrain (herbe longue, boue, boue sèche, herbe courte, etc.), vous pouvez répéter le même schéma. Rien ne vous empêche d’intégrer une telle logique dans le terrain lui-même en extrayant tous les états de terrain (herbe longue, herbe courte, boueuse, sèche, etc.) dans un nouveau FSM de terrain avec des transitions entre les états et peut-être de simples règles. Par exemple, pour arriver à l'état boueux, le moteur de règles doit vérifier le contexte pour rechercher des liquides, sinon ce n'est pas possible. Maintenant, DIEU est encore plus simple.

Vous pouvez compléter le système de FSM en les rendant autonomes et en leur donnant chacun un fil. Cette dernière étape n'est pas nécessaire, mais elle vous permet de modifier dynamiquement l'interaction du système en modifiant la manière dont vous déléguez votre prise de décision (lancement d'un FSM spécialisé ou simplement retour d'un état prédéterminé).

Rappelez-vous comment nous avons mentionné que les transitions pourraient aussi faire "d'autres tâches possibles"? Explorons cela en ajoutant la possibilité pour différents modèles (FSM) de communiquer les uns avec les autres. Vous pouvez définir un ensemble d'événements et autoriser chaque FSM à enregistrer un écouteur pour ces événements. Ainsi, si, par exemple, une vache entre dans un hex de terrain, il peut enregistrer des écouteurs pour les changements de transition. Ici, cela devient un peu délicat, car chaque FSM est implémenté à un très haut niveau sans aucune connaissance du domaine spécifique qu’il héberge. Cependant, vous pouvez y parvenir en demandant à la vache de publier une liste d'événements et la cellule peut s'enregistrer si elle voit les événements auxquels elle peut réagir. Une bonne hiérarchie de famille d’événement est un bon investissement.

Vous pouvez pousser plus loin encore en modélisant les niveaux de nutriments et le cycle de croissance de l'herbe, avec… vous l'aurez deviné… un FSM d'herbe intégré dans le propre modèle du terrain.

Si vous poussez l’idée suffisamment loin, DIEU n’a que très peu à faire car tous les aspects sont assez autogérés, ce qui vous permet de consacrer plus de temps à des activités plus pieuses.

résumer

Comme indiqué ci-dessus, le FSM n’est pas la solution, c’est juste un moyen d’illustrer que la solution à un tel problème ne se trouve pas dans le code mais à la manière dont vous modélisez votre problème. Il existe probablement d'autres solutions possibles et probablement bien meilleures que celles proposées par mon FSM. Cependant, l’approche "fractale" reste un bon moyen de gérer cette difficulté. Si cela est fait correctement, vous pouvez allouer dynamiquement des niveaux plus profonds là où cela compte tout en donnant des modèles plus simples là où cela compte moins. Vous pouvez mettre en file d'attente les modifications et les appliquer lorsque les ressources deviennent plus disponibles. Dans une séquence d'action, il peut ne pas être très important de calculer le transfert d'éléments nutritifs d'une vache à l'herbe. Vous pouvez cependant enregistrer ces transitions et appliquer les modifications ultérieurement ou simplement approximer avec une supposition éclairée en remplaçant simplement les moteurs de règles ou peut-être en remplaçant complètement l'implémentation de FSM par une version naïve plus simple pour les éléments qui ne sont pas dans le champ direct de intérêt (cette vache à l’autre bout du champ) à permettre des interactions plus détaillées pour obtenir le focus et une plus grande part des ressources. Tout cela sans jamais revoir le système dans son ensemble; comme chaque pièce est bien isolée, il devient plus facile de créer un remplacement immédiat limitant ou prolongeant la profondeur de votre modèle. En utilisant une conception standard, vous pouvez en tirer parti et maximiser les investissements réalisés dans des outils ad-hoc tels qu'un DSL pour définir des règles ou un vocabulaire standard pour les événements, en commençant à nouveau à un niveau très élevé et en ajoutant des améliorations au besoin. comme chaque pièce est bien isolée, il devient plus facile de créer un remplacement immédiat limitant ou prolongeant la profondeur de votre modèle. En utilisant une conception standard, vous pouvez en tirer parti et maximiser les investissements réalisés dans des outils ad-hoc tels qu'un DSL pour définir des règles ou un vocabulaire standard pour les événements, en commençant à nouveau à un niveau très élevé et en ajoutant des améliorations au besoin. comme chaque pièce est bien isolée, il devient plus facile de créer un remplacement immédiat limitant ou prolongeant la profondeur de votre modèle. En utilisant une conception standard, vous pouvez en tirer parti et maximiser les investissements réalisés dans des outils ad-hoc tels qu'un DSL pour définir des règles ou un vocabulaire standard pour les événements, en commençant à nouveau à un niveau très élevé et en ajoutant des améliorations au besoin.

Je donnerais un exemple de code, mais c’est tout ce que je peux me permettre de faire maintenant.


1
J'ai accepté cette réponse, car c'est un ordre de grandeur qui explique mieux une solution que les autres. Je pourrais cependant changer ma réponse acceptée si une meilleure se présentait. Votre solution semble également assez radicale pour faire la différence. Cependant, j'ai toujours du mal à comprendre comment définir les règles d'interaction entre les différents modèles. Pourriez-vous peut-être en faire un exemple?
David

-1 Je ne vois pas pourquoi cela ne peut pas être simplement résolu via un arbre de décision? (couplé avec un DSL qui prend le modèle et le transforme en code exécutable)?
Darknight le

14
DIEU vs les FSM?
John Cromartie

1
Les arbres de décision et les moteurs de règles sont utilisés précisément dans les cas où la modélisation des aspects actuels n’a aucune valeur intrinsèque car ils ne sont qu’un moyen de mettre fin à un calcul. Vous le voyez tout le temps dans les logiciels de santé. Cela dit, si vous essayez de modéliser le comportement réel, vous devriez essayer de le faire. Il y a des tonnes de cas où la seule logique à trouver dans un problème est le résultat de milliers de si cela alors que cela à l'infini. Et c’est valable, c’est pourquoi nous avons des outils pour y faire face.
delete_user

1
Cela s'est avéré très réussi dans le monde de la programmation de jeux; Il est beaucoup plus rapide et plus facile de modifier une règle ou une propriété et de laisser le comportement émerger, puis d'examiner une valeur pour décider de la façon dont elle doit agir.
Ben Leggiero

89

Il semble que toutes les déclarations conditionnelles dont vous parlez devraient être des données qui configurent votre programme plutôt que de faire partie de votre programme lui-même. Si vous pouvez les traiter ainsi, vous serez libre de modifier le fonctionnement de votre programme en modifiant simplement sa configuration au lieu de devoir modifier votre code et de recompiler chaque fois que vous souhaitez améliorer votre modèle.

Il existe de nombreuses manières de modéliser le monde réel, en fonction de la nature de votre problème. Vos diverses conditions peuvent devenir des règles ou des contraintes appliquées à la simulation. Au lieu d'avoir un code qui ressemble à:

if (sunLevel > 0.75) {
   foreach(cow in cows) {
       cow.desireForShade += 0.5;
   }
}
if (precipitation > 0.2) {
   foreach(cow in cows) {
       cow.desireForShelter += 0.8;
   }
}

vous pouvez plutôt avoir un code qui ressemble à:

foreach(rule in rules) {
   foreach (cow in cows) {
      cow.apply(rule);
   }
}

Ou, si vous pouvez développer un programme linéaire modélisant le comportement des vaches en fonction d'un certain nombre d'entrées, chaque contrainte peut devenir une ligne dans un système d'équations. Vous pouvez alors transformer cela en un modèle de Markov que vous pouvez itérer.

Il est difficile de dire quelle est la bonne approche pour votre situation, mais je pense que vous aurez beaucoup plus de facilité si vous considérez que vos contraintes sont des entrées dans votre programme et non du code.


4
Veuillez décrire comment "cow.apply (rule);" fonctionne avec les fichiers de configuration?
Kromster

8
@Krom, il est difficile de dire concrètement sans savoir de quel type de système nous parlons. Mon objectif ci-dessus est de traiter les milliers de conditions comme des entrées dans le programme afin que vous n'ayez pas à écrire de code pour chacune et que vous puissiez les modifier sans changer de programme. Mais oui, si les conditions peuvent être traitées comme des données, vous les stockeriez séparément du programme dans un document ou un fichier de configuration.
Caleb

2
@Krom - Simple. Vous liriez la règle puis l'appliqueriez à la vache donnée.
Ramhound

5
Déplacer du code dans des fichiers de configuration n'est pas toujours une bonne approche. La magie est difficile à déboguer.
Ricky Clarkson

44

Personne n'en a parlé, alors j'ai pensé le dire explicitement:

Des milliers de règles "Si .. Alors .. Sinon" sont le signe d'une application mal conçue.

Bien que la représentation de données spécifique à un domaine puisse ressembler à ces règles, êtes-vous absolument certain que votre implémentation doit ressembler à la représentation spécifique à un domaine?


18
Pas nécessairement vrai. Il y a des problèmes qui ne peuvent être résolus que par d'énormes arbres de décision. Mais bien sûr, une solution pour ceux qui se composent d'arborescence littérale de if-then-else est mal conçue. Il existe des moyens beaucoup plus flexibles et maintenables de le faire.
SF.

43
Je pensais que c'était le but de la question. Le PO a un problème spécifique à son domaine qui, dans une implémentation naïve, nécessiterait des milliers de si ... alors ... sinon. Il avait l'intuition que cela allait être gênant et a demandé à cette communauté de trouver de meilleurs moyens de le faire. Le simple fait que la question a été posée est un bon chant que cela était déjà compris, votre réponse, bien que correcte, n'aide en aucune façon la question.
Newtopian

@Newtopian Un utilisateur expérimenté ou un programmeur comprendrait cela et le prendrait pour évident. Un utilisateur ou un programmeur naïf pourrait ne pas s'en rendre compte, cependant. J'ai sciemment expliqué ce que la plupart des gens ici considèrent comme une évidence - j'ai confirmé que le PO était fondé à supposer que cela poserait un problème et ne devrait absolument pas aller de pair avec une mise en œuvre immédiate ou naïve.
blueberryfields

Je suis d'accord, vous pouvez remplacer si d'autre avec le polymorphisme ainsi que DI. Si vous avez des zillions de if else, votre design est toujours mauvais.
DarkVader

17

Veuillez utiliser des logiciels / langages informatiques adaptés à la tâche. Matlab est très souvent utilisé pour modéliser des systèmes complexes, où vous pouvez avoir littéralement des milliers de conditions. Ne pas utiliser les clauses if / then / else, mais par analyse numérique. R est un langage informatique open source qui contient des outils et des packages pour faire de même. Mais cela signifie également que vous devez reformuler votre modèle en termes plus mathématiques, afin de pouvoir inclure à la fois les influences principales et les interactions entre les influences dans les modèles.

Si vous ne l'avez pas déjà fait, suivez un cours sur la modélisation et la simulation. La dernière chose que vous devriez faire est d’envisager d’écrire un modèle comme celui-ci en termes de si-alors-sinon. Nous avons des chaînes de monte carlo markov, des machines à vecteurs de support, des réseaux de neurones, des analyses de variables latentes, ... S'il vous plaît, ne vous jetez pas 100 ans en arrière en ignorant toute la richesse des outils de modélisation dont vous disposez.


Je suis surpris de voir à quel point cette question a attiré si peu d'attention. L'analyse numérique et la modélisation sont au cœur d'une machine if-else. Cependant, il est sujet à de faux positifs qui peuvent ne pas être tolérés si l'application doit respecter scrupuleusement les règles. (Pensez bancaire)
Arun Jose

13

Les moteurs de règles peuvent être utiles car s’il ya tant de règles if / then, il peut être utile de les placer toutes à un emplacement en dehors du programme, où les utilisateurs peuvent les modifier sans avoir besoin de connaître un langage de programmation. En outre, des outils de visualisation peuvent être disponibles.

Vous pouvez également rechercher des solutions de programmation logique (comme Prolog). Vous pouvez rapidement modifier la liste des instructions if / then et lui demander de déterminer, par exemple, si une combinaison d’entrées conduirait à certains résultats, etc. code orienté objet).


11

Je me suis soudainement aperçu:

Vous devez utiliser un arbre d'apprentissage décisionnel (algorithme ID3).

Il est fort probable que quelqu'un l'ait implémenté dans votre langue. Sinon, vous pouvez porter une bibliothèque existante


Aller avec l'idée DSL donnée ci-dessus. Essayez de trouver un moyen d’abréger le problème en une forme d’algèbre symbolique, puis appliquez-le.
Zachary K

11

C’est plus une réponse du wiki de la communauté, regroupant les différents outils de modélisation suggérés par d’autres réponses, je viens d’ajouter des liens supplémentaires vers des ressources.

Je ne pense pas qu'il soit nécessaire de réaffirmer que vous devriez utiliser une approche différente pour des milliers d'instructions if / else codées en dur.


9

Chaque application volumineuse contient des milliers d' if-then-elseinstructions, sans compter les autres contrôles de flux. Ces applications sont toujours déboguées et gérées, en dépit de leur complexité.

En outre, le nombre d'instructions ne rend pas le flux imprévisible . La programmation asynchrone fait. Si vous utilisez des algorithmes déterministes de manière synchrone, vous aurez un comportement prévisible à 100%, à chaque fois.

Vous devriez probablement mieux expliquer ce que vous essayez de faire en cas de dépassement de capacité ou de révision de code, afin que les gens puissent vous suggérer les techniques de refactorisation précises à utiliser. Vous voudrez peut-être aussi poser des questions plus précises, telles que "Comment éviter d'imbriquer trop d' ifinstructions <avec un morceau de code>".


1
La plupart des applications ont 2 ou 3 niveaux de conditions d'imbrication et 1 ligne. Qu'en est-il d'un problème nécessitant un arbre de décision imbriqué de 50 niveaux, et de nombreuses conditions étant des composés logiques de 30 variables ou plus chacune?
SF.

Bien que "Chaque application volumineuse ..." soit certainement vrai, il est assez clair que le PO parle de longues séquences d'expressions conditionnelles qui forment essentiellement les règles d'un modèle. D'énormes groupes d' ifénoncés imbriqués deviennent rapidement, au mieux, difficiles à manier; une meilleure approche est donc nécessaire.
Caleb

@Caleb: vous avez raison, c'est clair maintenant , avec l'exemple précis au début de la question. Ce n'était pas avant que la question ait été modifiée lorsque j'ai écrit ma réponse. Cela explique l’incohérence réelle de ma réponse et de deux autres réponses affichées en même temps.
Arseni Mourzenko

2

Rendez votre application gérable en la concevant correctement. Concevez votre application en scindant les différentes logiques d’entreprise en classes / modules distincts. Ecrivez des tests unitaires qui testent chacune de ces classes / modules individuellement. Ceci est crucial et vous aidera à vous assurer que la logique métier est implémentée comme prévu.


2

Il n’y aura probablement pas un seul moyen de trouver une solution à votre problème, mais vous pouvez gérer sa complexité pièce par pièce si vous essayez de séparer différents domaines dans lesquels vous écrivez d’énormes blocs de déclarations if et appliquez des solutions. à chacun de ces petits problèmes.

Faites appel à des techniques telles que les règles évoquées dans le Refactoring pour trouver des moyens de décomposer des conditionnels volumineux en fragments gérables - plusieurs classes avec une interface commune peuvent remplacer une instruction case, par exemple.

Quitter tôt est une grande aide aussi. Si vous avez des conditions d'erreur, éliminez-les au début de la fonction en lançant une exception ou en retournant au lieu de les laisser imbriquer.

Si vous divisez vos conditions en fonctions de prédicats, il peut être plus facile de les suivre. En outre, si vous pouvez les obtenir dans un formulaire standard, il est peut-être possible de les insérer dans une structure de données construite de manière dynamique, au lieu d'une structure codée en dur.


2

Je suggérerais que vous utilisiez un moteur de règles. Dans le cas de Java, jBPM ou Oracle BPM peuvent être utiles. Les moteurs de règles vous permettent essentiellement de configurer l’application via XML.


+1 J'utilise Drools dernièrement avec Mvel comme langage pour exprimer les règles, et c'est exactement ce que vous recherchez. Malgré le fait que c'est très rapide.
Jalayn

Drools est un bon choix. Personnellement, j'utilise Oracle BPM en ce moment. Il y a aussi Feugo. Beaucoup d'outils open source et propriétaires sont disponibles.
Sid

2

Le problème n’est pas bien résolu par des "règles", qu’elles soient décrites par un code de procédure "if-then" ou par les nombreuses solutions de règles conçues pour les applications métiers. L'apprentissage automatique fournit un certain nombre de mécanismes pour modéliser de tels scénarios.

Fondamentalement, il faut formuler un schéma pour la représentation discrète des facteurs (par exemple, le soleil, le vent, la source de nourriture, les événements soudains, etc.) influençant le "système" (par exemple, les vaches dans un pâturage). Malgré la croyance erronée selon laquelle il est possible de créer une véritable représentation fonctionnelle valorisée, par opposition à un ordinateur discret, aucun ordinateur dans le monde réel (y compris le système nerveux humain) ne repose sur des valeurs réelles ou ne repose sur des valeurs réelles.

Une fois que vous avez votre représentation numérique des facteurs pertinents, vous pouvez construire l’un quelconque des modèles mathématiques. Je suggérerais un graphe bipartite où un ensemble de nœuds représente les vaches et l'autre une zone unitaire de pâturage. À tout moment, une vache occupe une surface unitaire de pâturage. Il existe alors pour chaque vache une valeur d'utilité associée au courant et à toutes les autres unités de pâturage. Si le modèle présuppose que la vache cherche à optimiser (par quelque moyen que ce soit pour la vache) la valeur d'utilité de son unité de pâturage, les vaches passeront d'une unité à l'autre dans un effort d'optimisation.

Un automate cellulaire fonctionne bien pour exécuter le modèle. Les mathématiques sous-jacentes dans le monde mathématique valorisé qui motivent le déplacement des vaches sont un modèle de gradient de champ. Les vaches passent de positions de moindre utilité perçue à des positions de plus grande valeur utilitaire.

Si l’on introduit un changement d’environnement dans le système, il ne passera pas à une solution stable de positionnement de la vache. Il deviendra également un modèle auquel des aspects de la théorie des jeux pourraient être appliqués; non pas que cela ajouterait nécessairement beaucoup à ce cas.

L’avantage ici est que l’abattage de vaches ou l’acquisition de nouvelles vaches peut être facilement géré en soustrayant et en ajoutant des cellules "vache" au graphe bipartite, alors que le modèle est en cours d’exécution.


1

Je ne pense pas que vous devriez définir autant de déclarations if-else. De mon point de vue, votre problème a plusieurs composantes:

  • Il doit être asynchrone ou multithread, car vous avez plusieurs vaches avec des personnalités différentes, une configuration différente. Chaque vache se demande dans quelle direction aller avant son prochain déménagement. À mon avis, un code de synchronisation est un outil médiocre pour résoudre ce problème.

  • La configuration de l'arbre de décision change constamment. Cela dépend de la position de la vache, de la météo, de l'heure, du terrain, etc. Au lieu de construire un arbre complexe si-sinon, je pense que nous devrions réduire le problème à une rose des vents ou à une fonction de direction - poids : Figure 1 figure 1 - direction - fonctions de poids pour certaines règles

    La vache doit toujours aller dans la direction qui a le plus grand poids total. Ainsi, au lieu de créer un grand arbre de décision, vous pouvez ajouter un ensemble de règles (avec des fonctions de direction / poids différentes) à chaque vache et simplement traiter le résultat à chaque fois que vous demandez la direction. Vous pouvez reconfigurer ces règles à chaque changement de position ou de passage du temps, ou vous pouvez ajouter ces détails en tant que paramètres, chaque règle doit être vérifiée. C'est une décision de mise en œuvre. Le moyen le plus simple d’obtenir une direction consiste à ajouter une simple boucle de 0 ° à 360 ° avec un pas de 1 °. Après cela, vous pouvez compter le poids total de chaque 360 ​​direction et exécuter une fonction max () pour obtenir la bonne direction.

  • Vous n'avez pas nécessairement besoin d'un réseau de neurones pour faire cela, juste une classe pour chaque règle, une classe pour les vaches, peut-être pour le terrain, etc ... et une classe pour le scénario (par exemple 3 vaches avec des règles différentes). 1 terrain spécifique). Figure 2 figure 2 - Noeuds de décision asynchrones de l'application pour vaches et connexions

    • rouge pour la direction de la messagerie - carte de poids à travers les règles
    • bleu pour les mises à jour d'orientation et de position après la prise de décision
    • vert pour les mises à jour des entrées après la mise à jour de l'orientation et de la position
    • noir pour obtenir des entrées

    remarque: vous aurez probablement besoin d'un framework de messagerie pour implémenter quelque chose comme ceci

    Donc, si faire de l’apprentissage des vaches ne fait pas partie de votre problème, vous n’avez pas besoin d’un réseau de neurones ni d’algorithmes génétiques. Je ne suis pas un expert en IA, mais je suppose que si vous voulez adapter vos vaches aux vraies, vous pouvez le faire simplement avec un algorithme génétique et les règles appropriées. Si je comprends bien, vous avez besoin d’une population de vaches avec des règles aléatoires. Ensuite, vous pouvez comparer le comportement de vaches réelles à celui de votre population modèle et en conserver 10%, ce qui est le plus proche des vrais. Après cela, vous pouvez ajouter de nouvelles contraintes de configuration des règles à votre usine de vaches en fonction des 10% que vous avez conservés, et ajouter de nouvelles vaches aléatoires à la population, etc.


0

J'ajouterais que si vous aviez vraiment des milliers de règles SI ... ALORS, vous pourriez peut-être trop spécifier. Pour ce qui en vaut la peine, les exposés sur la modélisation de réseaux neuronaux auxquels j'ai assisté commencent souvent par indiquer comment, avec "un ensemble de règles simples", ils peuvent générer un comportement assez complexe et raisonnablement proche de la réalité (des neurones réels en action, dans ces cas-là). Alors, êtes-vous sûrvous avez besoin de milliers de conditions? Je veux dire, en plus de 4 ou 5 aspects de la météo, de l'emplacement des sources de nourriture, des événements soudains, de l'élevage et du terrain, allez-vous vraiment avoir beaucoup plus de variables? Bien sûr, si vous tentiez de combiner toutes ces conditions avec toutes les permutations possibles, vous pourriez facilement avoir plusieurs milliers de règles, mais ce n'est pas la bonne approche. Peut-être qu'une approche de type logique floue dans laquelle les divers facteurs introduiraient un biais sur l'emplacement de chaque vache, combinée à une décision globale, vous permettrait de le faire avec beaucoup moins de règles.

Je conviens également avec tout le monde que le jeu de règles doit être séparé du flux général de code, de sorte que vous puissiez facilement le modifier sans changer le programme. Vous pouvez même proposer des règles concurrentes et voir comment elles se comportent contre les données réelles du mouvement des vaches. Cela semble amusant.


0

Des systèmes experts ont été mentionnés, qui sont un domaine de l'IA. Pour en savoir un peu plus, la lecture sur les moteurs d'inférence peut vous aider. Une recherche sur Google pourrait être plus utile - écrire la DSL est la partie la plus facile, vous pouvez le faire de manière triviale avec un analyseur tel que Gold Parser. La partie difficile provient de la constitution de votre arbre de décisions et de son exécution efficace.

De nombreux systèmes médicaux utilisent déjà ces moteurs, par exemple le site Web britannique NHS Direct .

Si vous êtes un .NET'er, Infer.NET peut vous être utile.


0

Depuis que vous regardez le mouvement de la vache, celle-ci est bloquée dans une direction à 360 degrés (les vaches ne peuvent pas voler.) Vous avez également un taux de déplacement. Ceci peut être défini comme un vecteur.

Maintenant, comment gérez-vous des choses comme la position du soleil, la pente de la colline, le bruit?

Chacun des degrés serait une variable indiquant le désir d'aller dans cette direction. Dites qu'une brindille se casse à droite de la vache à 90 degrés (en supposant que la vache fait face à 0 degrés). Le désir d'aller à droite diminuera et le désir d'aller 270 (à gauche) augmentera. Passez par tous les stimuli en ajoutant ou en soustrayant leur influence sur le désir des vaches d'aller dans une direction. Une fois que tous les stimuli sont appliqués, la vache ira dans la direction du désir le plus élevé.

Vous pouvez également appliquer des dégradés pour que les stimuli ne soient pas nécessairement binaires. Par exemple, une colline n'est pas droite dans une direction. Peut-être que la vache est dans une vallée ou sur une route sur une colline où son plat est tout droit, à 45 * légère montée à 90 * légère chute. A 180 * colline raide.

Vous pouvez ensuite ajuster le poids d'un événement et sa direction d'influence. Plutôt qu'une liste de si, alors vous avez un test qui cherche le maximum. De même, lorsque vous souhaitez ajouter un stimulus, vous pouvez simplement l'appliquer avant le test et vous n'avez pas à ajouter de plus en plus de complexité.

Plutôt que de dire que la vache ira dans n’importe quelle direction sur 360, la divisons en 36 directions. Chacun étant 10 degrés

Plutôt que de dire que la vache ira dans n'importe quelle direction sur 360, la divisons en 36 directions. Chacun étant 10 degrés. Selon votre degré de spécificité.


-2

Utilisez la POO. Pourquoi ne pas créer un groupe de classes qui gèrent les conditions de base et exécuter des méthodes aléatoires pour simuler ce que vous faites?

Obtenez un programmeur pour vous aider.

class COW_METHODS {

    Function = array('Action1','Action2',....'ActionX');

    function doAction() {
       execute(Function[random(1,5000]);
    }

    function execute(DynamicFunction) {
        exec(DynamicFunction());
    }

    Function Action1() {
        turnRight();
        eatGrass();
    }
    /*  keep adding functions for COW Methods ...  etc  */
    /*  and add classes for conditions inherit them as needed  */
    /*  keep an object to define conditions =  Singleton etc.  */
}

Pourquoi est-ce la dernière réponse. Nous en arrivons au fait, à savoir que des milliers de déclarations if else sont tout simplement maintenant une façon de concevoir un programme.
wfbarksdale

1
Parce que recommander " Utilisez OOP. Demandez à un programmeur de vous aider " vaut la même chose que de donner le conseil " Faites plus d'appels téléphoniques! " Lorsqu'on lui demande " Comment puis-je quadrupler mes ventes? ". Ce n'est pas strictement faux, mais cela n'aide pas beaucoup non plus.
JensG

2
J'ai voté parce que c'est une mauvaise réponse. Techniquement; votre réponse a peu à voir avec la programmation orientée objet. Une classe appelée COW_METHODSsemble n'être rien de plus qu'une collection de méthodes vaguement liées. Où est la séparation des préoccupations? En lien avec la question, en quoi cela aide-t-il le demandeur?
oɔɯǝɹ
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.