it-swarm.dev

Wie kann man Tausende von IF ... THEN ... ELSE-Regeln verwalten?

Ich denke darüber nach, eine Anwendung zu erstellen, die im Kern aus Tausenden von if ... then ... else-Anweisungen bestehen würde. Der Zweck der Anwendung besteht darin, vorhersagen zu können, wie sich Kühe in einer Landschaft bewegen. Sie sind von Dingen wie Sonne, Wind, Nahrungsquelle, plötzlichen Ereignissen usw. betroffen.

Wie kann eine solche Anwendung verwaltet werden? Ich stelle mir vor, dass es nach ein paar hundert IF-Anweisungen so gut wie unvorhersehbar wäre, wie das Programm reagieren würde, und das Debuggen, was zu einer bestimmten Reaktion führen würde, würde bedeuten, dass man jedes Mal den gesamten IF-Anweisungsbaum durchlaufen müsste.

Ich habe ein bisschen über Regel-Engines gelesen, aber ich sehe nicht, wie sie diese Komplexität umgehen würden.

215
David

Die logische Programmiersprache Prolog ist möglicherweise das, wonach Sie suchen. Ihre Problemstellung ist nicht spezifisch genug, damit ich beurteilen kann, ob sie gut passt, aber sie ähnelt eher Ihrer Aussage.

Ein Prolog-Programm besteht aus Fakten und Regeln, die angewendet werden. Hier ist eine einfache Beispielregel, die besagt: "Eine Kuh zieht an einen Ort, wenn die Kuh hungrig ist und am neuen Ort mehr Futter vorhanden ist als am alten Ort":

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

Alle Dinge in Großbuchstaben sind Variablen, Dinge, deren Wert Sie nicht kennen. Prolog versucht, Werte für diese Variablen zu finden, die alle Bedingungen erfüllen. Dieser Prozess wird mit einem leistungsstarken Algorithmus namens Unification durchgeführt, der das Herzstück von Prolog und ähnlichen logischen Programmierumgebungen bildet.

Zusätzlich zu den Regeln wird eine Datenbank mit Fakten bereitgestellt. Ein einfaches Beispiel, das mit den oben genannten Regeln funktioniert, könnte Folgendes sein:

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).

Beachten Sie, dass white_cow und pasture usw. nicht in Großbuchstaben geschrieben sind. Sie sind keine Variablen, sie sind Atome.

Schließlich stellen Sie eine Abfrage und fragen, was passieren wird.

?- 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

Die erste Abfrage fragt, wohin sich die weiße Kuh bewegen wird. Angesichts der obigen Regeln und Fakten lautet die Antwort Nein. Dies kann je nach Wunsch als "Ich weiß nicht" oder "Es bewegt sich nicht" interpretiert werden.

Die zweite Abfrage fragt, wohin sich die schwarze Kuh bewegt. Es bewegt sich auf die Weide, um zu essen.

Bei der letzten Abfrage wird gefragt, wohin sich alle Kühe bewegen. Als Ergebnis erhalten Sie alle möglichen (Kuh, Ziel), die Sinn machen. In diesem Fall bewegt sich der schwarze Bulle wie erwartet auf die Weide. Der verärgerte Bulle hat jedoch zwei Möglichkeiten, die den Regeln entsprechen. Er kann entweder auf die Weide oder in die Scheune ziehen.

Hinweis: Es ist Jahre her, seit ich Prolog das letzte Mal geschrieben habe. Alle Beispiele sind möglicherweise nicht syntaktisch gültig, aber die Idee sollte korrekt sein.

73
exDM69

Wenn Sie das Problem im Web angehen, können Sie eine Regelengine erstellen, in der jede bestimmte Regel unabhängig codiert wird. Eine weitere Verfeinerung hierfür wäre die Erstellung einer domänenspezifischen Sprache (DSL) zum Erstellen der Regeln. Ein DSL allein verschiebt das Problem jedoch nur von einer Codebasis (Haupt) zu einer anderen (DSL). Ohne Struktur wird das DSL nicht besser abschneiden als die Muttersprache (Java, C # usw.), daher werden wir darauf zurückkommen, nachdem wir einen verbesserten strukturellen Ansatz gefunden haben.

Das grundlegende Problem ist, dass Sie ein Modellierungsproblem haben. Immer wenn Sie auf solche kombinatorischen Situationen stoßen, ist dies ein klares Zeichen dafür, dass Ihre Modellabstraktion, die die Situation beschreibt, zu grob ist. Sie kombinieren höchstwahrscheinlich Elemente, die zu verschiedenen Modellen gehören sollten, in einer einzigen Entität.

Wenn Sie Ihr Modell immer wieder kaputt machen, lösen Sie diesen kombinatorischen Effekt schließlich vollständig auf. Wenn Sie diesen Weg einschlagen, ist es jedoch leicht, sich in Ihrem Design zu verlieren und ein noch größeres Durcheinander zu verursachen. Perfektionismus ist hier nicht unbedingt Ihr Freund.

Finite-State-Maschinen und Regel-Engines sind nur ein Beispiel dafür, wie dieses Problem gelöst und beherrschbarer gemacht werden kann. Die Hauptidee hier ist, dass ein guter Weg, um ein kombinatorisches Problem wie dieses zu beseitigen, häufig darin besteht, ein Design zu erstellen und es ad nauseam in verschachtelten Abstraktionsebenen zu wiederholen, bis Ihr System eine zufriedenstellende Leistung erbringt. Ähnlich wie Fraktale verwendet werden, um komplizierte Muster zu erstellen. Die Regeln bleiben gleich, egal ob Sie Ihr System mit einem Mikroskop oder aus der Vogelperspektive betrachten.

Beispiel für die Anwendung auf Ihre Domain.

Sie versuchen zu modellieren, wie sich Kühe durch ein Gelände bewegen. Obwohl Ihre Frage keine Details enthält, würde ich vermuten, dass Ihre große Anzahl von Wenns Entscheidungsfragmente wie if cow.isStanding then cow.canRun = true Enthält, aber Sie stecken fest, wenn Sie beispielsweise Details zum Gelände hinzufügen. Für jede Aktion, die Sie ausführen möchten, müssen Sie alle denkbaren Aspekte überprüfen und diese Überprüfungen für die nächste mögliche Aktion wiederholen.

Zuerst benötigen wir unser wiederholbares Design, das in diesem Fall ein FSM ist, um die sich ändernden Zustände der Simulation zu modellieren. Als erstes würde ich ein Referenz-FSM implementieren, das eine Zustandsschnittstelle definiert, einen Übergang Schnittstelle und möglicherweise ein Übergangskontext , der gemeinsam genutzte Informationen enthalten kann, die den beiden anderen zur Verfügung gestellt werden sollen. Eine grundlegende FSM-Implementierung wechselt unabhängig vom Kontext von einem Übergang zu einem anderen. Hier kommt eine Regelengine ins Spiel. Die Regelengine kapselt sauber die Bedingungen, die erfüllt sein müssen, wenn der Übergang stattfinden soll. Eine Regelengine kann hier so einfach sein wie eine Liste von Regeln, die jeweils eine Auswertungsfunktion haben, die einen Booleschen Wert zurückgibt. Um zu überprüfen, ob ein Übergang stattfinden soll, iterieren Sie die Liste der Regeln. Wenn einer von ihnen als falsch ausgewertet wird, findet der Übergang nicht statt. Der Übergang selbst enthält den Verhaltenscode , um den aktuellen Status des FSM (und anderer möglicher Aufgaben) zu ändern.

Wenn ich jetzt anfange, die Simulation als einzelnes großes FSM auf GOTT-Ebene zu implementieren, habe ich eine Menge möglicher Zustände, Übergänge usw. Das Wenn-Sonst-Chaos sieht aus, als wäre es behoben, aber es ist tatsächlich nur verteilt: Jede IF ist Jetzt eine Regel, die einen Test gegen eine bestimmte Information des Kontexts durchführt (die zu diesem Zeitpunkt so ziemlich alles enthält), und jeder IF-Körper befindet sich irgendwo im Übergangscode.

Geben Sie die Aufschlüsselung der Fraktale ein: Der erste Schritt besteht darin, für jede Kuh eine FSM zu erstellen, in der die Zustände die internen Zustände der Kuh sind (Stehen, Laufen, Gehen, Weiden usw.) und die Übergänge zwischen ihnen von der Umgebung beeinflusst werden. Es ist möglich, dass der Graph nicht vollständig ist, zum Beispiel ist die Beweidung nur im stehenden Zustand zugänglich, jeder andere Übergang wird abgelehnt, weil er einfach nicht im Modell vorhanden ist. Hier trennen Sie die Daten effektiv in zwei verschiedene Modelle, die Kuh und das Gelände. Jedes hat seine eigenen Eigenschaften. Mit dieser Aufschlüsselung können Sie Ihr gesamtes Motordesign vereinfachen. Anstatt nur eine einzige Regel-Engine zu haben, die alles entscheidet, haben Sie mehrere, einfachere Regel-Engines (eine für jeden Übergang), die über ganz bestimmte Details entscheiden. Viele Spielefirmen verwenden Finite-State-Maschinen wie diese, um über solche Aspekte zu entscheiden.

Da ich denselben Code für den FSM wieder verwende, handelt es sich im Grunde genommen um eine Konfiguration des FSM. Erinnern Sie sich, als wir DSLs früher erwähnt haben? Hier kann DSL viel Gutes bewirken, wenn Sie viele Regeln und Übergänge schreiben müssen.

Tiefer gehen

Jetzt muss GOTT nicht mehr mit der Komplexität der Verwaltung der inneren Zustände der Kuh fertig werden, aber wir können sie weiter vorantreiben. Die Verwaltung des Geländes ist zum Beispiel immer noch sehr komplex. Hier entscheiden Sie, wo die Aufteilung ausreicht. Wenn Sie zum Beispiel in Ihrem GOTT die Geländedynamik verwalten (langes Gras, Schlamm, trockener Schlamm, kurzes Gras usw.), können wir dasselbe Muster wiederholen. Nichts hindert Sie daran, eine solche Logik in das Gelände selbst einzubetten, indem Sie alle Geländezustände (langes Gras, kurzes Gras, schlammig, trocken usw.) in ein neues Gelände-FSM mit Übergängen zwischen den Zuständen und möglicherweise einfachen Regeln extrahieren. Um beispielsweise in den schlammigen Zustand zu gelangen, sollte die Regelengine den Kontext überprüfen, um Flüssigkeiten zu finden. Andernfalls ist dies nicht möglich. Jetzt wurde GOTT noch einfacher.

Sie können das FSM-System vervollständigen, indem Sie sie autonom machen und ihnen jeweils einen Thread geben. Dieser letzte Schritt ist nicht erforderlich, ermöglicht es Ihnen jedoch, die Interaktion des Systems dynamisch zu ändern, indem Sie anpassen, wie Sie Ihre Entscheidungsfindung delegieren (Starten eines spezialisierten FSM oder Zurückgeben eines festgelegten Status).

Erinnern Sie sich, wie wir erwähnt haben, dass Übergänge auch "andere mögliche Aufgaben" erledigen können? Lassen Sie uns dies untersuchen, indem wir die Möglichkeit hinzufügen, dass verschiedene Modelle (FSM) miteinander kommunizieren können. Sie können eine Reihe von Ereignissen definieren und jedem FSM erlauben, den Listener für diese Ereignisse zu registrieren. Wenn beispielsweise eine Kuh ein Geländefeld betritt, kann das Feld Zuhörer für Übergangsänderungen registrieren. Hier wird es etwas schwierig, weil jeder FSM auf sehr hohem Niveau implementiert wird, ohne die spezifische Domäne zu kennen, die er beherbergt. Sie können dies jedoch erreichen, indem die Kuh eine Liste von Ereignissen veröffentlicht und die Zelle sich registrieren kann, wenn sie Ereignisse sieht, auf die sie reagieren kann. Eine gute Hierarchie der Eventfamilie ist hier eine gute Investition. Wenn die Kuh anfängt zu grasen, kann das Gelände die Weidezeit aufzeichnen und nach einiger Zeit von langem Gras zu kurzem Gras übergehen, was der Kuh signalisiert, dass hier nichts mehr zu essen ist.

Sie können noch tiefer gehen, indem Sie den Nährstoffgehalt und den Wachstumszyklus von Gras modellieren, mit ... Sie haben es erraten ... einem Gras-FSM, das in das eigene Modell des Terrain-Patches eingebettet ist.

Wenn Sie die Idee weit genug vorantreiben, hat GOTT sehr wenig zu tun, da alle Aspekte so gut wie selbst verwaltet werden, wodurch Zeit für göttlichere Dinge frei wird.

Rekapitulieren

Wie oben erwähnt, ist der FSM hier nicht die Lösung, sondern nur ein Mittel, um zu veranschaulichen, dass die Lösung für ein solches Problem nicht im Code per say gefunden wird, sondern wie Sie Ihr Problem modellieren. Es gibt höchstwahrscheinlich andere Lösungen, die möglich und höchstwahrscheinlich viel besser sind als mein FSM-Vorschlag. Der "Fraktal" -Ansatz bleibt jedoch ein guter Weg, um diese Schwierigkeit zu bewältigen. Bei korrekter Ausführung können Sie tiefere Ebenen dynamisch zuweisen, wo es darauf ankommt, und einfachere Modelle angeben, wo es weniger wichtig ist. Sie können Änderungen in die Warteschlange stellen und anwenden, wenn Ressourcen verfügbarer werden. In einer Aktionssequenz ist es möglicherweise nicht so wichtig, den Nährstofftransfer von der Kuh zum Grasfeld zu berechnen. Sie können diese Übergänge jedoch aufzeichnen und die Änderungen zu einem späteren Zeitpunkt anwenden oder sich nur mit einer fundierten Vermutung annähern, indem Sie einfach die Regel-Engines ersetzen oder möglicherweise die FSM-Implementierung insgesamt durch eine einfachere naive Version für die Elemente ersetzen, die nicht im direkten Bereich von liegen Interesse (diese Kuh am anderen Ende des Feldes), detailliertere Interaktionen zu ermöglichen, um den Fokus und einen größeren Anteil an Ressourcen zu erhalten. All dies, ohne jemals das System als Ganzes zu überdenken; Da jedes Teil gut isoliert ist, ist es einfacher, einen Drop-In-Ersatz zu erstellen, der die Tiefe Ihres Modells begrenzt oder erweitert. Mithilfe eines Standarddesigns können Sie darauf aufbauen und die Investitionen in Ad-hoc-Tools wie DSL maximieren, um Regeln oder ein Standardvokabular für Ereignisse zu definieren. Beginnen Sie dabei wieder auf einem sehr hohen Niveau und fügen Sie nach Bedarf Verbesserungen hinzu.

Ich würde ein Codebeispiel liefern, aber das ist alles, was ich mir jetzt leisten kann.

140
Newtopian

Es hört sich so an, als ob all diese bedingten Anweisungen, von denen Sie sprechen, wirklich Daten sein sollten, die Ihr Programm konfigurieren und nicht Teil Ihres Programms selbst sind. Wenn Sie sie auf diese Weise behandeln können, können Sie die Funktionsweise Ihres Programms ändern, indem Sie lediglich die Konfiguration ändern, anstatt Ihren Code jedes Mal ändern und neu kompilieren zu müssen, wenn Sie Ihr Modell verbessern möchten.

Abhängig von der Art Ihres Problems gibt es viele verschiedene Möglichkeiten, die reale Welt zu modellieren. Ihre verschiedenen Bedingungen können zu Regeln oder Einschränkungen werden, die auf die Simulation angewendet werden. Anstatt Code zu haben, der aussieht wie:

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

sie können stattdessen Code haben, der wie folgt aussieht:

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

Wenn Sie ein lineares Programm entwickeln können, das das Verhalten der Kuh bei einer Reihe von Eingaben modelliert, wird jede Einschränkung möglicherweise zu einer Linie in einem Gleichungssystem. Sie können dies dann in ein Markov-Modell verwandeln, das Sie iterieren können.

Es ist schwer zu sagen, was der richtige Ansatz für Ihre Situation ist, aber ich denke, Sie werden es viel einfacher haben, wenn Sie Ihre Einschränkungen als Eingaben in Ihr Programm und nicht als Code betrachten.

90
Caleb

Niemand hat dies erwähnt, deshalb dachte ich, ich würde es explizit sagen:

Tausende von "If .. Then .. Else" -Regeln sind ein Zeichen für eine schlecht gestaltete Anwendung.

Während die domänenspezifische Datendarstellung möglicherweise wie diese Regeln aussieht, sind Sie absolut sicher, dass Ihre Implementierung der domänenspezifischen Darstellung ähneln sollte?

45
blueberryfields

Bitte verwenden Sie Software/Computersprachen, die für die Aufgabe geeignet sind. Matlab wird sehr oft verwendet, um komplexe Systeme zu modellieren, bei denen Sie tatsächlich buchstäblich Tausende von Bedingungen haben können. Nicht mit if/then/else-Klauseln, sondern durch numerische Analyse. R ist eine Open-Source-Computersprache, die mit Tools und Paketen gefüllt ist, um dasselbe zu tun. Dies bedeutet jedoch, dass Sie Ihr Modell auch mathematischer anpassen müssen, damit Sie sowohl die Haupteinflüsse als auch die Wechselwirkungen zwischen Einflüssen in Modelle einbeziehen können.

Wenn Sie es noch nicht getan haben, folgen Sie bitte einem Kurs über Modellierung und Simulation. Das Letzte, was Sie tun sollten, ist zu überlegen, ein solches Modell zu schreiben, wenn - dann - sonst. Wir haben Monte-Carlo-Markov-Ketten, Support-Vektor-Maschinen, neuronale Netze, Analyse latenter Variablen, ... Bitte werfen Sie sich nicht 100 Jahre zurück, indem Sie den Reichtum an verfügbaren Modellierungswerkzeugen ignorieren.

17
Joris Meys

Regel-Engines können hilfreich sein, da es bei so vielen if/then-Regeln hilfreich sein kann, sie alle an einem Ort außerhalb des Programms abzulegen, an dem Benutzer sie bearbeiten können, ohne eine Programmiersprache zu benötigen. Möglicherweise sind auch Visualisierungstools verfügbar.

Sie können sich auch logische Programmierlösungen (wie Prolog) ansehen. Sie können die Liste der if/then-Anweisungen schnell ändern und beispielsweise prüfen, ob eine Kombination von Eingaben zu bestimmten Ergebnissen führen würde usw. Es kann auch vorkommen, dass die Prädikatenlogik erster Ordnung sauberer ist als als prozeduraler Code (oder als as) objektorientierter Code).

13
psr

Mir ist plötzlich klar geworden:

Sie müssen einen Entscheidungslernbaum (ID3-Algorithmus) verwenden.

Es ist sehr wahrscheinlich, dass jemand es in Ihrer Sprache implementiert hat. Wenn nicht, können Sie eine vorhandene Bibliothek portieren

11
Darknight

Dies ist eher eine Community-Wiki-Antwort, die die verschiedenen Modellierungswerkzeuge zusammenfasst, die von anderen Antworten vorgeschlagen wurden. Ich habe gerade zusätzliche Links zu Ressourcen hinzugefügt.

Ich denke nicht, dass es notwendig ist, erneut zu betonen, dass Sie einen anderen Ansatz für Tausende von hartcodierten if/else-Anweisungen verwenden sollten.

11
ocodo

Jede große Anwendung enthält Tausende von if-then-else Anweisungen, ohne andere Flusssteuerungen, und diese Anwendungen werden trotz ihrer Komplexität weiterhin debuggt und verwaltet.

Auch die Anzahl der Anweisungen macht den Ablauf nicht unvorhersehbar . Asynchrone Programmierung funktioniert. Wenn Sie deterministische Algorithmen synchron verwenden, haben Sie jedes Mal ein zu 100% vorhersehbares Verhalten.

Sie sollten wahrscheinlich besser erklären , was Sie bei Stack Overflow oder Code Review tun möchten ), damit die Leute Ihnen die genauen Refactoring-Techniken vorschlagen können. Möglicherweise möchten Sie auch genauere Fragen stellen, z. B. "Wie vermeide ich, dass zu viele if -Anweisungen <mit einem bestimmten Code> verschachtelt werden?".

9

Ich würde vorschlagen, dass Sie eine Regel-Engine verwenden. Im Fall von Java kann jBPM oder Oracle BPM hilfreich sein. Mit Regel-Engines können Sie die Anwendung grundsätzlich über XML konfigurieren.

2
Sid

Das Problem lässt sich nicht gut durch "Regeln" lösen, sei es durch "Wenn-Dann" -Prozedurcode oder die zahlreichen Regellösungen, die für Geschäftsanwendungen entwickelt wurden. Maschinelles Lernen bietet eine Reihe von Mechanismen zur Modellierung solcher Szenarien.

Grundsätzlich muss ein Schema zur diskreten Darstellung der Faktoren (z. B. Sonne, Wind, Nahrungsquelle, plötzliche Ereignisse usw.) formuliert werden, die das "System" (d. H. Kühe auf einer Weide) beeinflussen. Ungeachtet der fehlgeleiteten Überzeugung, dass man im Gegensatz zu diskreten eine wirklich wertvolle funktionale Repräsentation erstellen kann, basiert kein Computer in der realen Welt (einschließlich des menschlichen Nervensystems) auf realen Werten oder berechnet auf realen Werten.

Sobald Sie Ihre numerische Darstellung für die relevanten Faktoren haben, können Sie eines von mehreren mathematischen Modellen erstellen. Ich würde einen zweigeteilten Graphen vorschlagen, bei dem ein Knotensatz Kühe und der andere eine Einheit Weidefläche darstellt. Eine Kuh besetzt auf jeden Fall eine Einheit Weidefläche. Für jede Kuh existiert dann ein Nutzwert, der der aktuellen und allen anderen Weideeinheiten zugeordnet ist. Wenn das Modell voraussetzt, dass die Kuh versucht, den Nutzwert ihrer Weideeinheit zu optimieren (was auch immer dies für die Kuh bedeutet), bewegen sich die Kühe von Einheit zu Einheit, um sie zu optimieren.

Eine zellulare Automatisierung eignet sich gut zur Ausführung des Modells. Die zugrunde liegende Mathematik in der wirklich geschätzten mathematischen Welt, die die Kuhbewegung motiviert, ist ein Feldgradientenmodell. Kühe bewegen sich von Positionen mit wahrgenommenem niedrigeren Nutzwert zu Positionen mit wahrgenommenem höheren Nutzwert.

Wenn man Umweltveränderungen in das System einspeist, bewegt es sich nicht zu einer stationären Lösung der Kuhpositionierung. Es wird auch ein Modell werden, auf das Aspekte der Spieltheorie angewendet werden könnten; nicht, dass dies notwendigerweise viel zu diesem Fall beitragen würde.

Der Vorteil hierbei ist, dass Schlachtkühe oder die Gewinnung neuer Kühe leicht verwaltet werden können, indem "Kuh" -Zellen zum zweigeteilten Diagramm subtrahiert und hinzugefügt werden, während das Modell ausgeführt wird.

2
charles

Machen Sie Ihre Anwendung überschaubar, indem Sie sie gut gestalten. Entwerfen Sie Ihre Anwendung, indem Sie die verschiedenen Geschäftslogiken in separate Klassen/Module aufteilen. Schreiben Sie Komponententests, die jede dieser Klassen/Module einzeln testen. Dies ist von entscheidender Bedeutung und hilft Ihnen sicherzustellen, dass die Geschäftslogik wie erwartet implementiert wird.

2
Bernard

Es wird wahrscheinlich keinen einzigen Weg geben, um Ihren Ausweg aus Ihrem Problem zu finden, aber Sie können die Komplexität Stück für Stück verwalten, wenn Sie versuchen, verschiedene Bereiche zu trennen, in denen Sie große Blöcke von if-Anweisungen schreiben und Lösungen anwenden zu jedem dieser kleineren Probleme.

Achten Sie auf Techniken wie die Regeln, über die in Refactoring für Möglichkeiten, große Bedingungen in verwaltbare Blöcke zu zerlegen - mehrere Klassen mit einer gemeinsamen Schnittstelle können beispielsweise eine case-Anweisung ersetzen.

Frühes Verlassen ist auch eine große Hilfe. Wenn Sie Fehlerbedingungen haben, können Sie diese zu Beginn der Funktion aus dem Weg räumen, indem Sie eine Ausnahme auslösen oder zurückkehren, anstatt sie verschachteln zu lassen.

Wenn Sie Ihre Bedingungen in Prädikatfunktionen aufteilen, ist es möglicherweise einfacher, diese zu verfolgen. Wenn Sie sie in eine Standardform bringen können, ist es möglicherweise auch möglich, sie in einer dynamisch erstellten Datenstruktur anstelle einer fest codierten zu erhalten.

2
Dan Monego

Ich denke nicht, dass Sie so viele if-else-Anweisungen definieren sollten. Aus meiner Sicht besteht Ihr Problem aus mehreren Komponenten:

  • Es sollte asynchron oder multithreaded sein, da Sie mehrere Kühe mit unterschiedlichen Persönlichkeiten und unterschiedlicher Konfiguration haben. Jede Kuh fragt sich, in welche Richtung sie vor ihrem nächsten Schritt gehen soll. Meiner Meinung nach ist ein Synchronisierungscode ein schlechtes Werkzeug für dieses Problem.

  • Die Konfiguration des Entscheidungsbaums ändert sich ständig. Es hängt von der Position der tatsächlichen Kuh, dem Wetter, der Zeit, dem Gelände usw. ab. Anstatt einen komplexen If-else-Baum zu bauen, sollten wir das Problem auf ein Windrose reduzieren = oder eine Richtungsgewichtsfunktion: figure 1  Abbildung 1 - Richtung - Gewichtsfunktionen für einige der Regeln

    Die Kuh sollte immer in die Richtung gehen, die das größte Summengewicht hat. Anstatt einen großen Entscheidungsbaum zu erstellen, können Sie jeder Kuh eine Reihe von Regeln (mit unterschiedlichen Richtungs- und Gewichtsfunktionen) hinzufügen und das Ergebnis einfach jedes Mal verarbeiten, wenn Sie nach der Richtung fragen. Sie können diese Regeln durch jede Positionsänderung oder durch Vergehen der Zeit neu konfigurieren oder Sie können diese Details als Parameter hinzufügen, die jede Regel erhalten sollte. Es ist eine Umsetzungsentscheidung. Der einfachste Weg, eine Richtung zu erhalten, besteht darin, eine einfache Schleife von 0 ° bis 360 ° mit einem Schritt von 1 ° hinzuzufügen. Danach können Sie das Gesamtgewicht jeder 360-Richtung zählen und eine max () -Funktion durchlaufen, um die richtige Richtung zu erhalten.

  • Sie benötigen dazu nicht unbedingt ein neuronales Netzwerk, nur eine Klasse für jede Regel, eine Klasse für die Kühe, möglicherweise für das Gelände usw. und eine Klasse für das Szenario (zum Beispiel 3 Kühe mit unterschiedlichen Regeln & 1 spezifisches Gelände). figure2  Abbildung 2 - Asynchrone Entscheidungsknoten und Verbindungen der Kuh-App

    • rot für Nachrichtenrichtung - Gewichtskarte durch die Regeln
    • blau für Orientierungs- und Positionsaktualisierungen nach der Entscheidungsfindung
    • grün für Eingabeaktualisierungen nach Orientierungs- und Positionsaktualisierung
    • schwarz zum Abrufen von Eingaben

    Hinweis: Sie benötigen wahrscheinlich ein Messaging-Framework, um so etwas zu implementieren

    Wenn die Herstellung von Lernkühen nicht Teil Ihres Problems ist, benötigen Sie weder ein neuronales Netzwerk noch genetische Algorithmen. Ich bin kein Experte für KI, aber ich denke, wenn Sie Ihre Kühe an die realen Kühe anpassen möchten, können Sie dies einfach mit einem genetischen Algorithmus und den richtigen Regeln tun. Wenn ich das gut verstehe, brauchen Sie eine Population von Kühen mit zufälligen Regeleinstellungen. Danach können Sie das Verhalten von echten Kühen mit dem Verhalten Ihrer Modellpopulation vergleichen und 10% behalten, die den nächsten Weg zu den realen gehen. Danach können Sie Ihrer Kuhfabrik neue Regelkonfigurationsbeschränkungen hinzufügen, basierend auf den 10%, die Sie behalten haben, und der Population neue zufällige Kühe hinzufügen usw., bis Sie eine Modellkuh erhalten, die sich genau wie die echten verhält ...

1
inf3rno

Ich würde hinzufügen, dass es der Fall sein könnte, dass Sie, wenn Sie wirklich Tausende von WENN ... DANN Regeln haben, möglicherweise zu genau spezifizieren. Für das, was es wert ist, beginnen Gespräche zur Modellierung neuronaler Netze, an denen ich teilgenommen habe, oft damit, zu erklären, wie sie mit "einfachen Regeln" ein ziemlich komplexes und einigermaßen realitätsgerechtes Verhalten erzeugen können (in diesen Fällen von echten Neuronen in Aktion). Also, sind Sie sicher Sie brauchen Tausende von Bedingungen? Ich meine, werden Sie neben 4-5 Aspekten des Wetters, der Lage der Nahrungsquellen, plötzlichen Ereignissen, des Hütens und des Geländes wirklich noch viele weitere Variablen haben? Sicher, wenn Sie versuchen würden, alle möglichen Permutationen zum Kombinieren dieser Bedingungen durchzuführen, könnten Sie leicht viele tausend Regeln haben, aber das ist nicht der richtige Ansatz. Vielleicht würde ein Ansatz im Fuzzy-Logik-Stil, bei dem die verschiedenen Faktoren eine Verzerrung des Standorts jeder Kuh hervorrufen, die zu einer Gesamtentscheidung führen, es Ihnen ermöglichen, dies in weitaus weniger Regeln zu tun.

Ich stimme auch allen anderen zu, dass der Regelsatz vom allgemeinen Codefluss getrennt sein sollte, damit Sie ihn problemlos optimieren können, ohne das Programm zu ändern. Sie könnten sogar konkurrierende Regelsätze entwickeln und sehen, wie sie sich gegen echte Kuhbewegungsdaten verhalten. Klingt lustig.

0
Chelonian

Es wurden Expertensysteme erwähnt, die ein Bereich der KI sind. Um diese ein wenig zu erweitern, kann Ihnen das Lesen von Inference Engines dabei helfen. Eine Google-Suche könnte nützlicher sein - das Schreiben von DSL ist der einfache Teil. Sie können dies trivial mit einem Parser wie Gold Parser tun. Der schwierige Teil besteht darin, einen Baum von Entscheidungen aufzubauen und diese effizient zu durchlaufen.

Viele medizinische Systeme verwenden diese Motoren bereits, zum Beispiel die britische NHS Direct-Website .

Wenn Sie ein .NET'er sind, kann Infer.NET für Sie nützlich sein.

0
Chris S

Da Sie die Bewegung der Kuh betrachten, stecken sie in 360-Grad-Richtung fest (Kühe können nicht fliegen). Sie haben auch eine Rate, die Sie reisen. Dies kann als Vektor definiert werden.

Wie gehen Sie nun mit Dingen wie Sonnenstand, Hanglage, lautem Lärm um?

Jeder der Grade wäre eine Variable, die den Wunsch anzeigt, in diese Richtung zu gehen. Sagen Sie a twig schnappt bei 90 Grad rechts von der Kuh (vorausgesetzt, die Kuh steht vor 0 Grad). Der Wunsch, nach rechts zu gehen, sinkt und der Wunsch, nach 270 zu gehen (links) wird steigen. Gehen Sie alle Reize durch, indem Sie ihren Einfluss auf den Wunsch der Kühe, in eine Richtung zu gehen, addieren oder subtrahieren. Sobald alle Reize angewendet werden, geht die Kuh in die Richtung des höchsten Verlangens.

Sie können auch Farbverläufe anwenden, damit die Stimuli nicht binär sein müssen. Zum Beispiel ist ein Hügel nicht gerade in eine Richtung. Vielleicht ist die Kuh in einem Tal oder auf einer Straße auf einem Hügel, wo sie flach geradeaus liegt, bei 45 * leicht bergauf bei 90 * leicht bergab. Bei 180 * steil bergauf.

Sie können dann das Gewicht eines Ereignisses und seine Einflussrichtung anpassen. Eher als eine Liste von wenn dann haben Sie einen Test, der nach dem max sucht. Auch wenn Sie einen Stimulus hinzufügen möchten, können Sie ihn einfach vor dem Test anwenden und müssen sich nicht mit dem Hinzufügen von immer mehr Komplexität befassen.

Anstatt zu sagen, dass die Kuh in eine beliebige 360-Richtung geht, können Sie sie einfach in 36 Richtungen aufteilen. Jeweils 10 Grad

Anstatt zu sagen, dass die Kuh in eine beliebige 360-Richtung geht, können Sie sie einfach in 36 Richtungen aufteilen. Jeweils 10 Grad. Je nachdem, wie spezifisch Sie sein müssen.

0
Zero