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

214

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 ist es, 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 ein 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.

David
quelle
22
Sie müssen einen Blick auf die DSL-Programmierung werfen: en.wikipedia.org/wiki/Domain-specific_language Außerdem können Sie möglicherweise eine datengesteuerte Meta-Rules-Engine erstellen. Sie könnten beispielsweise Modelle aus Daten generieren (z. B. Data-Mining-KDD)
Darknight,
14
google for "Expertensystem" und "rete net"; Viel Glück.
Steven A. Lowe
9
Verschieben Sie die fest codierten if / then-Anweisungen aus dem Quellcode in externe Daten, die die Simulation steuern.
Kwebble
6
Ich würde einige Werte in einer Textdatei puffern und eine Schleife verwenden, um eine HashMap mit Namen zu durchlaufen.
James P.
2
David-on-Programmierer-Fragen werden in CW konvertiert, wenn mehr als 15 Antworten gepostet werden. Wir können nicht kontrollieren, wer die 16. Antwort veröffentlicht.
ChrisF

Antworten:

73

Die logische Programmiersprache Prolog könnte das sein, wonach Sie suchen. Ihre Problemstellung ist für mich nicht spezifisch genug, um beurteilen zu können, ob sie gut passt, sie ähnelt jedoch 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 Hunger hat 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 Herz von Prolog und ähnlichen logischen Programmierumgebungen bildet.

Zusätzlich zu den Regeln wird eine Datenbank mit Fakten bereitgestellt. Ein einfaches Beispiel, das mit den obigen Regeln funktioniert, könnte etwa so aussehen:

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

Bei der ersten Abfrage wird gefragt, wohin sich die weiße Kuh bewegen soll. In Anbetracht 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.

In der letzten Abfrage wird gefragt, wohin sich alle Kühe bewegen. Als Ergebnis erhalten Sie alles Mögliche (Kuh, Ziel), das Sinn ergibt. In diesem Fall bewegt sich der schwarze Bulle erwartungsgemäß auf die Weide. Der wütende 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, dass ich Prolog das letzte Mal geschrieben habe. Möglicherweise sind alle Beispiele syntaktisch nicht gültig, aber die Idee sollte stimmen.

exDM69
quelle
10
-1: Ich glaube nicht, dass Prolog jemals die richtige Antwort sein kann. Ja, es könnte einfach sein, if-else-Regeln in Prolog abzurufen. Aber du wirst sicherlich noch etwas anderes tun müssen. Und egal was es ist (IO; GUI, Webentwicklung, ...), es wird ein Schmerz mit Prolog sein.
Martin Thoma
4
Check out learnprolognow.com Und das Einbetten von Prolog in eine andere Sprache ist viel einfacher als früher
Zachary K
@ ZacharyK: Verbindung ist unterbrochen.
RenniePet
@MartinThoma: kannst du deinen Kommentar erklären? Die Hauptprobleme bei Prolog IMHO sind das Fehlen von 1. einer deklarativen Methode zur Kontrolle der Suche und 2. der Eingabe. Aber wenn Ihre Anwendung nicht stark von diesen beiden abhängt, sehe ich a priori kein Problem mit der Verwendung von Prolog hier
SN
139

Zur Behebung des if-Web- Problems können Sie eine Regelengine erstellen, in der jede einzelne Regel unabhängig codiert wird. Eine weitere Verfeinerung hierfür wäre das Erstellen einer domänenspezifischen Sprache (DSL), um die Regeln zu erstellen. 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. Wann immer 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 sollen, in einer einzigen Entität.

Wenn Sie Ihr Modell immer wieder auflösen, wird sich dieser kombinatorische Effekt möglicherweise vollständig auflösen. Auf diesem Weg kann es jedoch leicht passieren, dass Sie sich in Ihrem Design verlieren und ein noch größeres Durcheinander schaffen. Perfektionismus ist hier nicht unbedingt Ihr Freund.

Finite State Machines und Rule Engines sind nur ein Beispiel dafür, wie dieses Problem aufgeschlüsselt und besser beherrschbar gemacht werden kann. Die Hauptidee dabei ist, dass ein kombinatorisches Problem wie dieses häufig vermieden werden kann, indem ein Entwurf erstellt und in verschachtelten Abstraktionsebenen ad-nauseam wiederholt wird, bis die Leistung Ihres Systems zufriedenstellend ist. Ä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 es Ihrer Frage an Details mangelt, würde ich vermuten, dass Ihre große Menge an Ifs Entscheidungsfragmente wie enthält, if cow.isStanding then cow.canRun = trueaber Sie geraten ins Stocken, wenn Sie beispielsweise Geländedetails hinzufügen. Für jede Aktion, die Sie durchführen möchten, müssen Sie alle Aspekte überprüfen, die Ihnen einfallen, 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. Das erste , was ich tun würde , ist eine Referenz FSM zu implementieren, einen prägenden Zustand Schnittstelle, eine Übergangsschnittstelle und vielleicht einen Übergang KontextDies kann gemeinsame Informationen enthalten, 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 die Bedingungen, die erfüllt sein müssen, damit der Übergang stattfinden kann. Eine Regel-Engine kann hier so einfach sein wie eine Liste von Regeln, von denen jede eine Auswertungsfunktion hat, die einen Booleschen Wert zurückgibt. Um zu überprüfen, ob ein Übergang stattfinden soll, iterieren Sie die Liste der Regeln, und wenn eine davon als falsch bewertet wird, findet der Übergang nicht statt. Der Übergang selbst enthält den Verhaltenscode zum Ändern des aktuellen Status des FSM (und anderer möglicher Aufgaben).

Wenn ich jetzt beginne, die Simulation als eine einzelne große FSM auf GOD-Ebene zu implementieren, habe ich am Ende VIELE mögliche Zustände, Übergänge usw. Das If-else-Durcheinander sieht aus, als wäre es behoben, aber es ist eigentlich nur verteilt: Jedes IF ist Jetzt eine Regel, die einen Test mit einer bestimmten Information des Kontexts durchführt (die zu diesem Zeitpunkt so ziemlich alles enthält) und jeder WENN-Körper sich irgendwo im Übergangscode befindet.

Geben Sie die Aufschlüsselung der Fraktale ein: Der erste Schritt wäre, eine FSM für jede Kuh zu erstellen, bei 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 würden. Es ist möglich, dass das Diagramm nicht vollständig ist, zum Beispiel, dass die Beweidung nur im stehenden Zustand zugänglich ist, und dass jeder andere Übergang nicht zulässig ist, 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 mit eigenen Eigenschaften. Mit dieser Aufschlüsselung können Sie Ihr gesamtes Motordesign vereinfachen. Anstelle einer einzigen Regelengine, die über alles entscheidet, stehen jetzt mehrere einfachere Regelengines (eine für jeden Übergang) zur Verfügung, die über ganz bestimmte Details entscheiden.

Da ich denselben Code für die FSM wiederverwende, handelt es sich im Grunde genommen um eine Konfiguration der FSM. Erinnerst du dich, als wir DSL's 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 ganzen Komplexität im Umgang mit den inneren Zuständen der Kuh fertig werden, sondern wir können sie weiter vorantreiben. Zum Beispiel ist die Verwaltung des Geländes immer noch sehr komplex. Hier entscheiden Sie, wo die Aufteilung ausreicht. Wenn Sie beispielsweise in Ihrem GOTT die Geländedynamik (langes Gras, Schlamm, trockener Schlamm, kurzes Gras usw.) verwalten, 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, matschig, trocken usw.) in ein neues Gelände-FSM mit Übergängen zwischen den Zuständen und möglicherweise einfachen Regeln extrahieren. Um zum Beispiel in den schlammigen Zustand zu gelangen, sollte die Regel-Engine den Kontext prü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 zuweisen. Dieser letzte Schritt ist nicht erforderlich, ermöglicht es Ihnen jedoch, die Interaktion des Systems dynamisch zu ändern, indem Sie die Art und Weise anpassen, in der Sie Ihre Entscheidungen delegieren (einen speziellen FSM starten oder einfach einen festgelegten Status zurückgeben).

Erinnern Sie sich, wie wir erwähnt haben, dass Übergänge auch "andere mögliche Aufgaben" erfüllen können? Lassen Sie uns das untersuchen, indem wir die Möglichkeit hinzufügen, dass verschiedene Modelle (FSM) miteinander kommunizieren. Sie können eine Reihe von Ereignissen definieren und jedem FSM erlauben, Listener für diese Ereignisse zu registrieren. Betritt beispielsweise eine Kuh ein Geländefeld, kann das Feld Listener für Übergangsänderungen registrieren. Hier wird es etwas knifflig, da jeder FSM auf sehr hohem Niveau implementiert wird, ohne die spezifische Domäne zu kennen, die er besitzt. Sie können dies jedoch erreichen, indem die Kuh eine Liste von Ereignissen veröffentlicht und die Zelle registriert, wenn sie Ereignisse sieht, auf die sie reagieren kann. Eine gute Hierarchie der Veranstaltungsfamilie ist hier eine gute Investition.

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 Modell des Terrain Patch eingebettet ist.

Wenn Sie die Idee weit genug treiben, hat GOTT sehr wenig zu tun, da alle Aspekte so gut wie selbst verwaltet werden und 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 zu finden ist, 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, wenn es darauf ankommt, und einfachere Modelle angeben, wenn es darauf ankommt. 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, die Nährstoffübertragung von der Kuh auf die Rasenfläche zu berechnen. Sie können diese Übergänge jedoch aufzeichnen und die Änderungen zu einem späteren Zeitpunkt anwenden oder sie mit einer fundierten Vermutung nur annähern, indem Sie einfach die Regelengines ersetzen oder die FSM-Implementierung insgesamt durch eine einfachere, naive Version für die Elemente ersetzen, die sich nicht im direkten Bereich von befinden Interesse (diese Kuh am anderen Ende des Feldes), damit detailliertere Interaktionen den Fokus und einen größeren Anteil an Ressourcen erhalten. All dies, ohne jemals das System als Ganzes zu überdenken; Da jedes Teil gut isoliert ist, ist es einfacher, ein Drop-In-Ersatzelement zu erstellen, das die Tiefe Ihres Modells begrenzt oder erweitert. Durch die Verwendung 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 erneut auf sehr hohem Niveau und erweitern Sie diese nach Bedarf. Da jedes Teil gut isoliert ist, ist es einfacher, ein Drop-In-Ersatzelement zu erstellen, das die Tiefe Ihres Modells begrenzt oder erweitert. Durch die Verwendung 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 erneut auf sehr hohem Niveau und erweitern Sie diese nach Bedarf. Da jedes Teil gut isoliert ist, ist es einfacher, ein Drop-In-Ersatzelement zu erstellen, das die Tiefe Ihres Modells begrenzt oder erweitert. Durch die Verwendung 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 erneut auf sehr hohem Niveau und erweitern Sie diese nach Bedarf.

Ich würde ein Codebeispiel angeben, aber das ist alles, was ich mir leisten kann, um es jetzt zu tun.

Newtopian
quelle
1
Ich habe diese Antwort akzeptiert, weil es eine Größenordnung besser ist, eine Lösung zu erklären als die anderen. Ich könnte jedoch meine akzeptierte Antwort ändern, wenn eine bessere auftaucht. Ihre Lösung scheint auch radikal genug zu sein, um einen Unterschied zu machen. Ich habe jedoch immer noch Probleme zu verstehen, wie die Regeln für die Interaktion der verschiedenen Modelle definiert werden sollen. Könnten Sie vielleicht ein Beispiel dafür geben?
David
-1 Ich verstehe nicht, warum dies nicht einfach über einen Entscheidungsbaum gelöst werden kann? (in Verbindung mit einem DSL, das das Modell in ausführbaren Code umwandelt)?
Darknight,
14
GOTT gegen die FSM?
John Cromartie
1
Entscheidungsbäume und Regelmaschinen werden genau dann verwendet, wenn die Modellierung der vorliegenden Aspekte keinen Wert hat, da sie lediglich ein Mittel zum Zweck einer Berechnung sind. Sie sehen dies die ganze Zeit in der Gesundheitssoftware. Das heißt, wenn Sie versuchen, das tatsächliche Verhalten zu modellieren, sollten Sie versuchen, dies zu tun. Es gibt Unmengen von Fällen, in denen die einzige Logik, die in einem Problem gefunden werden kann, das Ergebnis von Tausenden von Fällen ist, wenn dies dann ad infinitum ist. Und es ist gültig, deshalb haben wir Werkzeuge, um damit umzugehen.
Deleted_user
1
Dies hat sich in der Welt der Spieleprogrammierung als sehr erfolgreich erwiesen. Es ist viel schneller und einfacher, eine Regel oder Eigenschaft zu ändern und das Verhalten entstehen zu lassen, und dann einen Wert zu untersuchen, um zu entscheiden, wie darauf reagiert werden soll.
Ben Leggiero
89

Es hört sich so an, als ob all diese bedingten Anweisungen, von denen Sie sprechen, Daten sein sollten, die Ihr Programm konfigurieren, und nicht Teil Ihres Programms. Wenn Sie sie so behandeln können, können Sie die Funktionsweise Ihres Programms ändern, indem Sie einfach die Konfiguration ändern, anstatt den 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 so aussieht:

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 von Kühen bei einer Reihe von Eingaben modelliert, wird jede Einschränkung möglicherweise zu einer Linie in einem Gleichungssystem. Sie können das dann in ein Markov-Modell umwandeln, 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.

Caleb
quelle
4
Bitte beschreiben Sie, wie "cow.apply (rule);" funktioniert das mit config files?
Kromster
8
@Krom, es ist schwer konkret zu sagen, ohne zu wissen, über was für ein System wir eigentlich sprechen. Mein Punkt oben ist, die Tausenden von Bedingungen als Eingaben in das Programm zu behandeln, damit Sie nicht für jede Code schreiben müssen und die Bedingungen ändern können, ohne das Programm zu ändern. Aber ja, wenn die Bedingungen als Daten behandelt werden können, speichern Sie sie getrennt vom Programm in einer Art Dokument oder Konfigurationsdatei.
Caleb
2
@Krom - Einfach. Sie würden die Regel lesen und dann auf die angegebene Kuh anwenden.
Ramhound
5
Das Verschieben von Code in Konfigurationsdateien ist nicht immer ein guter Ansatz. Magic ist schwer zu debuggen.
Ricky Clarkson
44

Niemand hat das erwähnt, also dachte ich, ich würde es explizit sagen:

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

Obwohl die domänenspezifische Datendarstellung wie diese Regeln aussehen könnte, sind Sie sich absolut sicher, dass Ihre Implementierung der domänenspezifischen Darstellung ähneln sollte?

Blueberryfields
quelle
18
Nicht unbedingt wahr. Es gibt Probleme, die nur durch enorme Entscheidungsbäume gelöst werden können. Aber natürlich ist eine Lösung für diejenigen, die aus dem wörtlichen Baum des Wenn-Dann-Anderen bestehen, eine schlecht gestaltete. Es gibt viel flexiblere und wartbarere Möglichkeiten, dies zu tun.
SF.
43
Ich dachte, das war der Punkt der Frage. Das OP hat ein spezifisches Problem für seine Domäne, das bei einer naiven Implementierung Tausende von anderen erfordern würde, wenn ... dann .... Er ahnte, dass dies ärgerlich sein würde und erkundigte sich bei dieser Community nach besseren Möglichkeiten, dies zu tun. Die bloße Tatsache, dass die Frage gestellt wurde, ist ein gutes Zeichen dafür, dass dies bereits verstanden wurde. Ihre Antwort hilft in keiner Weise der Frage, obwohl sie richtig ist.
Newtopian
@Newtopian Ein fortgeschrittener Benutzer oder Programmierer würde das verstehen und es als offensichtlich ansehen. Ein naiver Benutzer oder Programmierer könnte dies jedoch nicht erkennen. Ich erklärte wissentlich, was die meisten Leute hier für offensichtlich halten - ich bestätigte, dass das OP in seiner Annahme, dass dies problematisch wäre und definitiv nicht mit der sofortigen oder naiven Implementierung einhergehen sollte, richtig ist.
blueberryfields
Ich bin damit einverstanden, Sie können, wenn sonst mit Polymorphismus sowie DI ersetzen. Wenn Sie zig Millionen von haben, wenn sonst, ist Ihr Design sehr schlecht.
DarthVader
17

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

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

Joris Meys
quelle
Ich bin überrascht, dass diese Frage so wenig Beachtung findet. Die numerische Analyse und Modellierung ist das Herzstück einer If-else-Maschine. Es weist jedoch falsche Positive auf, die möglicherweise nicht toleriert werden, wenn die Anwendung die strikte Einhaltung von Regeln erfordert. (Think Banking)
Arun Jose
13

Regel-Engines könnten hilfreich sein, da es bei so vielen if / then-Regeln hilfreich sein könnte, sie alle an einem Ort außerhalb des Programms abzulegen, wo Benutzer sie bearbeiten können, ohne dass sie eine Programmiersprache 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 z. B. prüfen lassen, 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 Prozedurcode (oder als objektorientierter Code).

bA
quelle
11

Mir ist plötzlich aufgefallen:

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

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

Dunkle Nacht
quelle
Gehen Sie mit der oben angegebenen DSL-Idee. Versuchen Sie herauszufinden, wie Sie das Problem zu einer Form einer symbolischen Algebra abstrahieren können, und implementieren Sie diese.
Zachary K
11

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

Ich glaube nicht, dass Sie noch einmal betonen müssen, dass Sie einen anderen Ansatz für Tausende von hartcodierten if / else-Anweisungen verwenden sollten.

ocodo
quelle
9

Jede große Anwendung enthält Tausende von if-then-elseAnweisungen, andere Ablaufsteuerungen nicht eingerechnet, und diese Anwendungen werden trotz ihrer Komplexität weiterhin getestet und gewartet.

Auch die Anzahl der Anweisungen macht den Fluss nicht unvorhersehbar . Asynchrone Programmierung. Wenn Sie deterministische Algorithmen synchron verwenden, ist das Verhalten jedes Mal zu 100% vorhersehbar.

Sie sollten wahrscheinlich besser erklären, was Sie mit 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 das Verschachteln von zu vielen ifAnweisungen <mit einem bestimmten Code>".

Arseni Mourzenko
quelle
1
Die meisten Apps verfügen über 2-3 Verschachtelungsstufen und 1-Zeilen-Bedingungen. Was ist mit einem Problem, bei dem ein Entscheidungsbaum 50 Ebenen tiefer verschachtelt sein muss und viele Bedingungen logische Verbindungen von jeweils 30 oder mehr Variablen sind?
SF.
Während "Jede große Anwendung ..." mit Sicherheit zutrifft, ist es ziemlich klar, dass es sich beim OP um lange Sequenzen von bedingten Ausdrücken handelt, die im Wesentlichen die Regeln in einem Modell bilden. Riesige verschachtelte Gruppen von ifAnweisungen werden bestenfalls schnell unhandlich, sodass ein besserer Ansatz erforderlich ist.
Caleb
@Caleb: Sie haben recht, es ist jetzt klar , mit dem genauen Beispiel am Anfang der Frage. Erst als ich meine Antwort schrieb, wurde die Frage bearbeitet. Dies erklärt die tatsächliche Inkohärenz meiner und zweier gleichzeitig geposteter Antworten.
Arseni Mourzenko
2

Machen Sie Ihre Anwendung übersichtlich, 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 dabei, sicherzustellen, dass die Geschäftslogik wie erwartet implementiert wird.

Bernard
quelle
2

Es wird wahrscheinlich keinen einzigen Weg geben, um Ihr Problem zu lösen, aber Sie können die Komplexität Stück für Stück bewältigen, 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.

Sehen Sie sich Techniken wie die in Refactoring beschriebenen an, um herauszufinden, wie Sie große Bedingungen in überschaubare Teile aufteilen können. Beispielsweise können mehrere Klassen mit einer gemeinsamen Schnittstelle eine case-Anweisung ersetzen.

Ein früher Ausstieg ist auch eine große Hilfe. Wenn Sie Fehlerbedingungen haben, beseitigen Sie diese am Anfang der Funktion, 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, den Überblick zu behalten. Wenn Sie sie in ein Standardformular einbinden können, können Sie sie möglicherweise auch in eine dynamisch erstellte Datenstruktur einbinden, anstatt in eine fest codierte.

Dan Monego
quelle
2

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

Sid
quelle
+1 Ich habe in letzter Zeit Drools zusammen mit Mvel als die Sprache zum Ausdrücken der Regeln verwendet, und es ist genau das, wonach Sie suchen. Ungeachtet der Tatsache, dass es sehr schnell ist.
Jalayn
Drools ist eine gute Wahl. Ich persönlich benutze gerade Oracle BPM. Es gibt auch Feugo. Viele Open Source- und Propriety-Tools verfügbar.
Sid
2

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

Grundsätzlich muss man ein Schema für die diskrete Darstellung der Faktoren (z. B. Sonne, Wind, Nahrungsquelle, plötzliche Ereignisse usw.) formulieren, die das "System" beeinflussen (dh Kühe auf einer Weide). Ungeachtet der fehlgeleiteten Überzeugung, dass man eine echte funktionale Repräsentation erstellen kann, ist kein Computer in der realen Welt (einschließlich des menschlichen Nervensystems) echtwertbasiert oder berechnet basierend auf echten Werten.

Sobald Sie Ihre numerische Darstellung für die relevanten Faktoren haben, können Sie eines von mehreren mathematischen Modellen konstruieren. Ich würde einen zweigliedrigen Graphen vorschlagen, bei dem eine Gruppe von Knoten Kühe und die andere eine Einheitsweidefläche darstellt. Eine Kuh nimmt in jedem Fall eine bestimmte Weidefläche ein. 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 eine Optimierung zu erreichen.

Ein zellularer Automat eignet sich gut zum Ausführen des Modells. Die zugrunde liegende Mathematik in der real geschätzten mathematischen Welt, die die Kuhbewegung motiviert, ist ein Feldgradientenmodell. Kühe bewegen sich von Positionen mit einem wahrgenommenen niedrigeren Nutzwert zu Positionen mit einem wahrgenommenen 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 diesem Fall notwendigerweise viel hinzufügen würde.

Der Vorteil hierbei ist, dass Schlachtkühe oder die Gewinnung neuer Kühe problemlos verwaltet werden können, indem "Kuh" -Zellen vom zweigliedrigen Graphen abgezogen und hinzugefügt werden, während das Modell ausgeführt wird.

Charles
quelle
1

Ich denke nicht, dass Sie so viele if-else-Anweisungen definieren sollten. Aus meiner Sicht hat Ihr Problem mehrere 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 gehen soll, bevor sie weitergeht. 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 meiner Meinung nach auf eine Windrose oder eine Richtungsgewichtsfunktion reduzieren : Abbildung 1 Abbildung 1 - Richtungsgewichtungsfunktionen für einige Regeln

    Die Kuh sollte immer in die Richtung gehen, die das größte Summengewicht hat. Anstatt also einen großen Entscheidungsbaum zu erstellen, können Sie jeder Kuh ein Regelwerk (mit unterschiedlichen Richtungs- und Gewichtsfunktionen) hinzufügen und das Ergebnis bei jeder Richtungsanfrage einfach verarbeiten. Sie können diese Regeln durch jede Positionsänderung oder durch Verstreichen der Zeit neu konfigurieren oder diese Details als Parameter hinzufügen, die jede Regel erhalten sollte. Es ist eine Umsetzungsentscheidung. Der einfachste Weg, eine Richtung zu bestimmen, ist das Hinzufügen einer einfachen Schleife von 0 ° bis 360 ° mit 1 ° -Schritt. Danach können Sie das Summengewicht jeder 360-Richtung zählen und eine max () -Funktion durchlaufen, um die richtige Richtung zu ermitteln.

  • Sie brauchen dazu nicht unbedingt ein neuronales Netz, nur eine Klasse für jede Regel, eine Klasse für die Kühe, vielleicht für das Gelände usw. und eine Klasse für das Szenario (zum Beispiel 3 Kühe mit unterschiedlichen Regeln & 1 bestimmtes Gelände). Figur 2 Abbildung 2 - Asynchrone Entscheidungsknoten und -verbindungen der Cow 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, um Eingaben zu erhalten

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

    Wenn das Bilden von Lernkühen nicht zu Ihrem Problem gehört, benötigen Sie weder ein neuronales Netzwerk noch genetische Algorithmen. Ich bin kein Experte für KI, aber wenn Sie Ihre Kühe an die realen anpassen möchten, können Sie dies einfach mit einem genetischen Algorithmus und den richtigen Regeln tun. Wenn ich es richtig verstehe, brauchen Sie eine Population von Kühen mit zufälligen Regeleinstellungen. Danach können Sie das Verhalten echter Kühe mit dem Verhalten Ihrer Modellpopulation vergleichen und 10% beibehalten, die dem tatsächlichen Verhalten am nächsten kommen. 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 ...

inf3rno
quelle
0

Ich würde hinzufügen, dass es der Fall sein könnte, wenn Sie wirklich Tausende von WENN ... DANN-Regeln haben, könnten Sie eine Überspezifikation haben. Für das, was es wert ist, beginnen Gespräche über die Modellierung neuronaler Netze, an denen ich oft teilgenommen habe, mit der Feststellung, wie sie mit "einfachen Regeln" ein ziemlich komplexes und einigermaßen realitätsnahes Verhalten (von in Aktion befindlichen echten Neuronen) erzeugen können. Also, bist du dir sicher?Sie brauchen Tausende von Bedingungen? Ich meine, abgesehen von 4-5 Aspekten des Wetters, der Lage der Nahrungsquellen, plötzlichen Ereignissen, Hüten und des Geländes, werden Sie wirklich viel mehr Variablen haben? Sicher, wenn Sie versuchen würden, alle möglichen Kombinationen dieser Bedingungen zu erstellen, 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 bewirken und zu einer Gesamtentscheidung führen, es Ihnen ermöglichen, dies mit weitaus weniger Regeln zu tun.

Ich stimme auch allen anderen zu, dass der Regelsatz vom allgemeinen Code-Fluss getrennt sein sollte, damit Sie ihn leicht optimieren können, ohne das Programm zu ändern. Sie könnten sogar mit konkurrierenden Regelsätzen aufwarten und sehen, wie diese sich auf die tatsächlichen Bewegungsdaten der Kuh auswirken. Klingt lustig.

Chelonian
quelle
0

Expertensysteme wurden erwähnt, die einen Bereich der KI darstellen. Wenn Sie diese näher erläutern möchten, hilft Ihnen möglicherweise das Nachlesen von Inference Engines . Eine Google-Suche könnte nützlicher sein - das Schreiben der DSL ist der einfache Teil, Sie könnten dies trivial mit einem Parser wie Gold Parser tun. Der schwierige Teil besteht darin, Ihren Entscheidungsbaum aufzubauen und effizient durchzuarbeiten.

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

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

Chris S
quelle
0

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, mit der Sie reisen. Dies kann als Vektor definiert werden.

Wie geht man 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. Angenommen, ein Zweig schnappt bei 90 Grad rechts von der Kuh (vorausgesetzt, die Kuh steht vor 0 Grad). Der Wunsch, nach rechts zu gehen, wird sinken und der Wunsch, nach 270 (links) zu gehen, wird steigen. Gehen Sie alle Reize durch, indem Sie ihren Einfluss auf den Wunsch der Kühe, in eine Richtung zu gehen, addieren oder abziehen. Sobald alle Reize angewendet sind, 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 gerade aus ist, bei 45 * leicht bergauf bei 90 * leicht bergab. Bei 180 * steil bergauf.

Sie können dann das Gewicht eines Ereignisses und seine Einflussrichtung anpassen. Anstelle einer Liste von if thens haben Sie einen Test, der nach der max. 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, teilen wir sie einfach in 36 Richtungen auf. Jeweils 10 Grad

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

Null
quelle
-2

Verwenden Sie OOP. Wie wäre es, wenn Sie eine Reihe von Klassen erstellen, die mit den Basisbedingungen umgehen und zufällige Methoden ausführen, um zu simulieren, was Sie tun.

Bitten Sie einen Programmierer um Hilfe.

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.  */
}
Dylan Rosario
quelle
Warum ist das die letzte Antwort? Es kommt auf den Punkt, dass Tausende von if else-Anweisungen jetzt einfach die Möglichkeit bieten, ein Programm zu entwerfen.
wfbarksdale
1
Weil die Empfehlung " Verwenden Sie OOP. Lassen Sie sich von einem Programmierer helfen. " Den gleichen Wert hat wie die Empfehlung " Tätigen Sie mehr Anrufe! ", Wenn Sie gefragt werden " Wie kann ich meine Verkäufe vervierfachen? ". Es ist nicht unbedingt falsch, aber es hilft auch nicht viel.
JensG
2
Ich habe abgestimmt, weil das eine schlechte Antwort ist. Technisch; Ihre Antwort hat wenig mit OOP zu tun. Eine aufgerufene Klasse COW_METHODSscheint nichts weiter zu sein als eine Sammlung lose verwandter Methoden. Wo ist die Trennung der Anliegen? In Bezug auf die Frage, wie hilft dies dem Fragesteller?
30.