Come si possono gestire migliaia di regole IF ... THEN ... ELSE?


214

Sto prendendo in considerazione la creazione di un'applicazione, che, in sostanza, consisterebbe in migliaia di istruzioni if ​​... then ... else. Lo scopo dell'applicazione è quello di essere in grado di prevedere come le mucche si muovono in qualsiasi paesaggio. Sono influenzati da cose come il sole, il vento, la fonte di cibo, eventi improvvisi ecc.

Come può essere gestita un'applicazione del genere? Immagino che dopo alcune centinaia di dichiarazioni IF, sarebbe altrettanto imprevedibile il modo in cui il programma avrebbe reagito e il debug di ciò che avrebbe portato a una certa reazione avrebbe significato che si sarebbe dovuto attraversare l'intero albero delle istruzioni IF ogni volta.

Ho letto un po 'di motori delle regole, ma non vedo come possano aggirare questa complessità.


22
È necessario dare un'occhiata alla programmazione DSL: en.wikipedia.org/wiki/Domain-specific_language Inoltre è possibile creare un motore di regole metereologiche basato sui dati. Ad esempio, potresti generare modelli dai dati (ad esempio, data mining KDD)
Darknight,

14
google per "sistema esperto" e "rete net"; in bocca al lupo.
Steven A. Lowe,

9
Spostare le istruzioni if ​​/ then codificate dal codice sorgente in dati esterni che guidano la simulazione.
Kwebble,

6
Metterei alcuni valori in un file di testo e utilizzerei un ciclo per passare attraverso una HashMap contenente nomi.
James P.

2
David: le domande dei programmatori vengono convertite in CW quando vengono pubblicate più di 15 risposte. Non possiamo controllare chi pubblica la 16a risposta.
ChrisF

Risposte:


73

Il linguaggio di programmazione logica Prolog potrebbe essere quello che stai cercando. La tua affermazione sul problema non è abbastanza specifica per me per valutare se è adatta, ma è piuttosto simile a quello che dici.

Un programma Prolog è costituito da fatti e regole applicati. Ecco una semplice regola di esempio che afferma "Una mucca si sposta in una posizione se la mucca ha fame e c'è più cibo nella nuova posizione che nella vecchia posizione":

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

Tutte le cose in lettere maiuscole sono variabili, cose di cui non conosci il valore. Prolog tenta di trovare valori per queste variabili che soddisfino tutte le condizioni. Questo processo viene eseguito con un potente algoritmo chiamato unificazione che è il cuore di Prolog e ambienti di programmazione logica simili.

Oltre alle regole, viene fornito un database di fatti. Un semplice esempio che funziona con le regole sopra potrebbe essere qualcosa di simile:

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

Notare che white_cow e pascoli, ecc. Non sono scritti in maiuscolo. Non sono variabili, sono atomi.

Alla fine fai una domanda e chiedi cosa succederà.

?- 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 prima query chiede dove si sposterà la mucca bianca. Date le regole e i fatti sopra, la risposta è No. Questo può essere interpretato come "Non lo so" o "Non si muove" a seconda di ciò che si desidera.

La seconda query chiede dove si sposta la mucca nera. Si sposta al pascolo per mangiare.

L'ultima domanda chiede dove si muovono tutte le mucche. Di conseguenza ottieni tutto il possibile (Mucca, Destinazione) che ha senso. In questo caso il toro nero si sposta sul pascolo come previsto. Tuttavia, il toro arrabbiato ha due scelte che soddisfano le regole, può spostarsi al pascolo o al fienile.

Nota: sono passati anni dall'ultima volta che ho scritto Prolog, tutti gli esempi potrebbero non essere sintatticamente validi ma l'idea dovrebbe essere corretta.


10
-1: Non credo che Prolog possa mai essere la risposta giusta. Sì, potrebbe essere facile ottenere le regole if-else in Prolog. Ma sicuramente dovrai fare qualcos'altro. E non importa quale sia (IO; GUI, sviluppo web, ...) sarà un dolore con Prolog.
Martin Thoma,

4
Dai un'occhiata a learnprolognow.com E incorporare il prologo in un'altra lingua è molto più semplice di prima
Zachary K

@ZacharyK: il collegamento è interrotto.
RenniePet,

@MartinThoma: puoi spiegare il tuo commento? I principali problemi con Prolog IMHO sono la mancanza di 1. un modo dichiarativo di controllare la ricerca e 2. la digitazione. Ma se la tua domanda non dipende molto da questi due, allora non vedo a priori un problema con l'utilizzo di Prolog qui
SN

139

Affrontando il problema if web è possibile creare un motore di regole in cui ogni specifica regola è codificata in modo indipendente. Un ulteriore affinamento per questo sarebbe quello di creare un linguaggio specifico di dominio (DSL) per creare le regole, tuttavia un solo DSL sposta solo il problema da una base di codice (principale) a un'altra (DSL). Senza struttura, il DSL non andrà meglio della lingua madre (Java, C # ecc.), Quindi torneremo ad esso dopo aver trovato un approccio strutturale migliorato.

Il problema fondamentale è che stai riscontrando un problema di modellizzazione. Ogni volta che incontri situazioni combinatorie come questa è un chiaro segno che l'astrazione del tuo modello che descrive la situazione è troppo approssimativa. Molto probabilmente stai combinando elementi che dovrebbero appartenere a diversi modelli in una singola entità.

Se continui a scomporre il tuo modello alla fine dissolverai completamente questo effetto combinatorio. Tuttavia, quando prendi questa strada, è facile perdersi nel tuo design creando un pasticcio ancora più grande, il perfezionismo qui non è necessariamente tuo amico.

Le macchine a stati finiti e i motori delle regole sono solo un esempio di come questo problema può essere scomposto e reso più gestibile. L'idea principale qui è che un buon modo per sbarazzarsi di un problema combinatorio come questo è spesso quello di creare un disegno e ripeterlo fino alla nausea in livelli annidati di astrazione fino a quando il sistema non si esibisce in modo soddisfacente. Simile a come i frattali vengono utilizzati per creare modelli intricati. Le regole rimangono invariate, indipendentemente dal fatto che si guardi il proprio sistema al microscopio o dall'alto.

Esempio di applicazione di questo al tuo dominio.

Stai cercando di modellare il modo in cui le mucche si muovono attraverso un terreno. Sebbene la tua domanda manchi di dettagli, immagino che la tua grande quantità di if includa frammenti di decisione come if cow.isStanding then cow.canRun = truema ti impantanerai mentre aggiungi dettagli del terreno, ad esempio. Quindi, per ogni azione che si desidera intraprendere, è necessario verificare tutti gli aspetti a cui è possibile pensare e ripetere queste verifiche per la successiva azione possibile.

Innanzitutto abbiamo bisogno del nostro design ripetibile, che in questo caso sarà un FSM per modellare gli stati mutevoli della simulazione. Quindi la prima cosa che vorrei fare è implementare un FSM di riferimento, definendo un'interfaccia di stato , un'interfaccia di transizione e forse un contesto di transizioneche può contenere informazioni condivise da rendere disponibili alle altre due. Un'implementazione di base di FSM passerà da una transizione all'altra indipendentemente dal contesto, è qui che entra in gioco un motore di regole. Il motore di regole incapsula in modo chiaro le condizioni che devono essere soddisfatte se deve avvenire la transizione. Un motore di regole qui può essere semplice come un elenco di regole ognuna con una funzione di valutazione che restituisce un valore booleano. Per verificare se deve avvenire una transizione, ripetiamo l'elenco delle regole e se una di esse viene valutata come falsa, la transizione non ha luogo. La transizione stessa conterrà il codice comportamentale per modificare lo stato corrente dell'FSM (e altre possibili attività).

Ora, se comincio a implementare la simulazione come un singolo grande FSM a livello di DIO, finirò con MOLTISSIMI possibili stati, transizioni ecc. ora una regola che esegue un test su una specifica informazione del contesto (che a questo punto contiene praticamente tutto) e ogni corpo IF si trova da qualche parte nel codice di transizione.

Inserisci la ripartizione dei frattali: il primo passo sarebbe quello di creare un FSM per ogni mucca in cui gli stati sono gli stati interni della mucca (in piedi, correre, camminare, pascolare ecc.) E le transizioni tra di loro sarebbero influenzate dall'ambiente. È possibile che il grafico non sia completo, ad esempio il pascolo è accessibile solo dallo stato permanente, qualsiasi altra transizione viene dissalata perché semplicemente assente dal modello. Qui separa efficacemente i dati in due diversi modelli, la mucca e il terreno. Ognuno con le proprie proprietà impostate. Questa suddivisione ti consentirà di semplificare la progettazione generale del motore. Ora invece di avere un singolo motore di regole che decide tutto quello che hai più, più semplici motori di regole (uno per ogni transizione) che decidono su dettagli molto specifici.

Poiché sto riutilizzando lo stesso codice per FSM, questa è fondamentalmente una configurazione di FSM. Ricordi quando abbiamo menzionato DSL prima? È qui che la DSL può fare molto bene se hai molte regole e transizioni da scrivere.

Andando più in profondità

Ora DIO non ha più a che fare con tutta la complessità nella gestione degli stati interni della mucca, ma possiamo spingerci oltre. C'è ancora molta complessità nella gestione del terreno, ad esempio. Qui è dove decidi dove è sufficiente la ripartizione. Se ad esempio nel tuo DIO finisci per gestire la dinamica del terreno (erba lunga, fango, fango secco, erba corta ecc.) Possiamo ripetere lo stesso schema. Non c'è nulla che ti impedisca di incorporare tale logica nel terreno stesso estraendo tutti gli stati del terreno (erba lunga, erba corta, fangoso, secco, ecc.) In un nuovo terreno FSM con transizioni tra gli stati e forse semplici regole. Ad esempio, per arrivare allo stato fangoso il motore delle regole dovrebbe controllare il contesto per trovare liquidi, altrimenti non è possibile. Ora DIO è diventato ancora più semplice.

È possibile completare il sistema di FSM rendendoli autonomi e dando a ciascuno di essi un thread. Quest'ultimo passaggio non è necessario ma ti consente di modificare dinamicamente l'interazione del sistema regolando il modo in cui deleghi il tuo processo decisionale (avvio di un FSM specializzato o solo ritorno di uno stato predeterminato).

Ricordi come abbiamo detto che le transizioni potrebbero anche svolgere "altri possibili compiti"? Esploriamo ciò aggiungendo la possibilità per diversi modelli (FSM) di comunicare tra loro. È possibile definire un set di eventi e consentire a ciascun FSM di registrare il listener per questi eventi. Pertanto, se, ad esempio, una mucca entra in un esagono di terreno, l'esagono può registrare gli ascoltatori per i cambiamenti di transizione. Qui diventa un po 'complicato perché ogni FSM è implementato a un livello molto alto senza alcuna conoscenza del dominio specifico che ospita. Tuttavia è possibile ottenere ciò facendo in modo che la mucca pubblichi un elenco di eventi e la cella può registrarsi se vede eventi a cui può reagire. Una buona gerarchia della famiglia di eventi qui è un buon investimento.

Puoi approfondire ancora modellando i livelli di nutrienti e il ciclo di crescita dell'erba, con ... hai indovinato ... un FSM di erba incorporato nel modello del cerotto del terreno.

Se spingi l'idea abbastanza lontano, DIO ha ben poco da fare in quanto tutti gli aspetti sono praticamente autogestiti, liberando tempo da dedicare a cose più divine.

Ricapitolare

Come indicato sopra, la FSM qui non è la soluzione, ma solo un mezzo per illustrare che la soluzione a tale problema non si trova nel codice per dire, ma come si modella il problema. Ci sono probabilmente altre soluzioni possibili e molto probabilmente molto meglio della mia proposta di FSM. Tuttavia, l'approccio dei "frattali" rimane un buon modo per gestire questa difficoltà. Se eseguito correttamente, è possibile allocare dinamicamente livelli più profondi laddove conta, fornendo modelli più semplici laddove conta di meno. È possibile mettere in coda le modifiche e applicarle quando le risorse diventano più disponibili. In una sequenza d'azione potrebbe non essere così importante calcolare il trasferimento di nutrienti dalla mucca all'erba. Puoi comunque registrare queste transizioni e applicare le modifiche in un secondo momento o semplicemente approssimare con un'ipotesi istruita semplicemente sostituendo i motori delle regole o forse sostituendo l'implementazione di FSM del tutto con una versione ingenua più semplice per gli elementi che non sono nel campo diretto di interesse (quella vacca all'altra estremità del campo) per consentire interazioni più dettagliate per ottenere il focus e una maggiore quota di risorse. Tutto ciò senza mai rivisitare il sistema nel suo insieme; poiché ogni parte è ben isolata diventa più facile creare un rimpiazzo di sostituzione che limiti o estenda la profondità del modello. Usando un design standard puoi basarti su questo e massimizzare gli investimenti fatti in strumenti ad-hoc come un DSL per definire regole o un vocabolario standard per eventi, iniziando di nuovo a un livello molto alto e aggiungendo i perfezionamenti necessari. poiché ogni parte è ben isolata diventa più facile creare un rimpiazzo di sostituzione che limiti o estenda la profondità del modello. Usando un design standard puoi basarti su questo e massimizzare gli investimenti fatti in strumenti ad-hoc come un DSL per definire regole o un vocabolario standard per eventi, iniziando di nuovo a un livello molto alto e aggiungendo i perfezionamenti necessari. poiché ogni parte è ben isolata diventa più facile creare un rimpiazzo di sostituzione che limiti o estenda la profondità del modello. Usando un design standard puoi basarti su questo e massimizzare gli investimenti fatti in strumenti ad-hoc come un DSL per definire regole o un vocabolario standard per eventi, iniziando di nuovo a un livello molto alto e aggiungendo i perfezionamenti necessari.

Vorrei fornire un esempio di codice, ma questo è tutto ciò che posso permettermi di fare in questo momento.


1
Ho accettato questa risposta, perché è un ordine di grandezza migliore per spiegare una soluzione rispetto alle altre. Potrei, tuttavia, modificare la mia risposta accettata se ne compare una migliore. La tua soluzione sembra anche abbastanza radicale da fare la differenza. Tuttavia, ho ancora problemi a capire come definire le regole su come i diversi modelli dovrebbero interagire. Potresti forse fare un esempio di questo?
David,

-1 Non vedo perché questo non possa essere semplicemente risolto tramite un albero decisionale? (accoppiato con una DSL che prende il modello e lo trasforma in codice eseguibile)?
Darknight,

14
DIO vs il FSM?
John Cromartie,

1
Gli alberi decisionali e i motori delle regole vengono utilizzati proprio nei casi in cui non esiste un valore intrinseco per modellare gli aspetti a portata di mano in quanto sono semplicemente un mezzo per un fine di un calcolo. Lo vedi sempre nel software sanitario. Detto questo, se stai cercando di modellare il comportamento reale, dovresti provare a farlo. Ci sono tonnellate di casi in cui l'unica logica che si trova in un problema è il risultato di migliaia di se questo poi quell'infinito. Ed è valido, ecco perché abbiamo strumenti per affrontarlo.
delete_user

1
Ciò si è rivelato molto efficace nel mondo della programmazione di giochi; è molto più veloce e più semplice cambiare una regola o una proprietà e lasciare emergere il comportamento, quindi esaminare un valore per decidere come agire su di essa.
Ben Leggiero,

89

Sembra che tutte queste affermazioni condizionali di cui stai parlando debbano essere dati che configurano il tuo programma piuttosto che parte del programma stesso. Se riesci a trattarli in quel modo, sarai libero di modificare il modo in cui il tuo programma funziona semplicemente cambiando la sua configurazione invece di dover modificare il tuo codice e ricompilare ogni volta che vuoi migliorare il tuo modello.

Esistono molti modi diversi per modellare il mondo reale, a seconda della natura del problema. Le diverse condizioni potrebbero diventare regole o vincoli applicati alla simulazione. Invece di avere un codice simile a:

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

puoi invece avere un codice simile a:

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

Oppure, se è possibile sviluppare un programma lineare che modella il comportamento della mucca dato un numero di input, ogni vincolo potrebbe diventare una linea in un sistema di equazioni. Potresti quindi trasformarlo in un modello Markov che puoi iterare.

È difficile dire quale sia l'approccio giusto per la tua situazione, ma penso che avrai un tempo molto più facile se consideri i tuoi vincoli come input per il tuo programma e non per codice.


4
Descrivi come "cow.apply (rule);" funziona con i file di configurazione?
Kromster,

8
@Krom, è difficile dirlo in termini concreti senza sapere di quale tipo di sistema stiamo effettivamente parlando. Il mio punto sopra è trattare le migliaia di condizioni come input per il programma in modo da non dover scrivere codice per ognuno e poter cambiare le condizioni senza cambiare il programma. Ma sì, se le condizioni possono essere trattate come dati, le archivieresti separatamente dal programma in una sorta di documento o file di configurazione.
Caleb,

2
@Krom - Semplice. Leggere la regola e applicarla alla mucca data.
Ramhound,

5
Spostare il codice in file di configurazione non è sempre un buon approccio. La magia è difficile da eseguire il debug.
Ricky Clarkson,

44

Nessuno lo ha menzionato, quindi ho pensato di dirlo esplicitamente:

Migliaia di regole "If .. Then .. Else" sono un segno di un'applicazione mal progettata.

Mentre la rappresentazione dei dati specifici del dominio potrebbe assomigliare a queste regole, sei assolutamente certo che l'implementazione dovrebbe assomigliare alla rappresentazione specifica del dominio?


18
Non necessariamente vero. Ci sono problemi che possono essere risolti solo attraverso enormi alberi decisionali. Ma ovviamente una soluzione per quelli composti dall'albero letterale di if-then-else è mal progettata. Esistono modi molto più flessibili e sostenibili per farlo.
SF.

43
Ho pensato che fosse questo il punto della domanda. L'OP ha un problema specifico al suo dominio che, in un'implementazione ingenua, richiederebbe migliaia di se ... allora ... altro. Aveva un'intuizione che questo doveva essere problematico e chiese a questa comunità qui i modi migliori per farlo. Il solo fatto che la domanda sia stata posta è una buona notizia che questo era già stato compreso, la tua risposta, sebbene corretta, non aiuta in alcun modo la domanda.
Newtopian,

@Newtopian Un utente avanzato o un programmatore lo capiranno e lo considererebbero ovvio. Tuttavia, un utente o un programmatore ingenuo potrebbe non rendersene conto. Ho consapevolmente dichiarato ciò che la maggior parte delle persone qui considera ovvio: ho confermato che l'OP ha ragione nel ritenere che ciò sarebbe problematico e non dovrebbe assolutamente andare con l'implementazione immediata o ingenua.
Blueberryfields,

Sono d'accordo, è possibile sostituire se altro con polimorfismo e DI. se hai miliardi di se, il tuo design è molto cattivo.
DarthVader,

17

Utilizzare i linguaggi software / computer adatti all'attività. Matlab è usato molto spesso per modellare sistemi complessi, dove è possibile avere letteralmente migliaia di condizioni. Non usando le clausole if / then / else, ma mediante analisi numerica. R è un linguaggio informatico open source pieno di strumenti e pacchetti per fare lo stesso. Ciò significa che devi anche riformulare il tuo modello in termini più matematici, in modo da poter includere sia le influenze principali sia le interazioni tra influenze nei modelli.

Se non l'hai già fatto, segui un corso su modellazione e simulazione. L'ultima cosa che dovresti fare è considerare di scrivere un modello come quello in termini di if - then - else. Abbiamo catene di monte carlo markov, macchine vettoriali di supporto, reti neurali, analisi delle variabili latenti, ... Ti preghiamo di non buttarti indietro di 100 anni ignorando la ricchezza degli strumenti di modellazione che hai a disposizione.


Sono sorpreso di come questa domanda abbia avuto così poca attenzione. L'analisi e la modellazione numerica sono al centro di una macchina if-else. Tuttavia, soffre di falsi positivi che potrebbero non essere tollerati se l'applicazione richiede il rigoroso rispetto delle regole. (Pensa al settore bancario)
Arun Jose,

13

I motori delle regole potrebbero essere utili perché se ci sono così tante regole if / then potrebbe essere utile metterle tutte in un posto al di fuori del programma in cui gli utenti possano modificarle senza conoscere un linguaggio di programmazione. Inoltre, potrebbero essere disponibili strumenti di visualizzazione.

Potresti anche esaminare le soluzioni di programmazione logica (come Prolog). È possibile modificare rapidamente l'elenco di istruzioni if ​​/ then e fare in modo che ciò accada se una combinazione di input porterebbe a determinati risultati, ecc. Potrebbe anche accadere che sia più pulito nella logica del predicato del primo ordine che come codice procedurale (o rispetto a come codice orientato agli oggetti).


11

Mi è improvvisamente venuto in mente:

È necessario utilizzare un albero di apprendimento decisionale (algoritmo ID3).

È molto probabile che qualcuno l'abbia implementato nella tua lingua. Altrimenti potresti portare una libreria esistente


Vai con l'idea DSL di cui sopra. Prova a capire come sottrarre il problema a una forma di Algebra simbolica, quindi implementalo.
Zaccaria K,


9

Ogni grande applicazione contiene migliaia di if-then-elseistruzioni, senza contare gli altri controlli di flusso, e tali applicazioni sono ancora sottoposte a debug e mantenute, nonostante la loro complessità.

Inoltre, il numero di istruzioni non rende imprevedibile il flusso . La programmazione asincrona lo fa. Se usi gli algoritmi deterministici in modo sincrono, avrai sempre un comportamento prevedibile al 100%.

Probabilmente dovresti spiegare meglio cosa stai cercando di fare su Stack Overflow o Code Review in modo che le persone possano suggerirti le tecniche precise di refactoring da usare. Potresti anche fare domande più precise, come "Come evitare di annidare troppe ifistruzioni <dato un pezzo di codice>".


1
La maggior parte delle app ha 2-3 livelli di nidificazione e condizioni a 1 riga. Che dire di un problema che richiede un albero decisionale annidato di 50 livelli e molte condizioni sono composti logici di 30 o più variabili ciascuno?
SF.

Mentre "Ogni grande applicazione ..." è certamente vero, è abbastanza chiaro che l'OP sta parlando di lunghe sequenze di espressioni condizionali che essenzialmente formano le regole in un modello. Enormi gruppi di ifaffermazioni nidificate diventano rapidamente ingombranti nella migliore delle ipotesi, quindi è necessario un approccio migliore.
Caleb,

@Caleb: hai ragione, è chiaro ora , con l'esempio preciso all'inizio della domanda. Non è stato prima che la domanda fosse modificata quando ho scritto la mia risposta. Questo spiega l'effettiva incoerenza della mia e di altre due risposte pubblicate contemporaneamente.
Arseni Mourzenko,

2

Rendi gestibile la tua applicazione progettandola bene. Progetta la tua applicazione suddividendo le varie logiche aziendali in classi / moduli separati. Scrivi unit test che testano ciascuna di queste classi / moduli singolarmente. Questo è fondamentale e ti aiuterà a garantire che la logica aziendale sia implementata come previsto.


2

Probabilmente non ci sarà un unico modo per risolvere il problema, ma puoi gestirne la complessità pezzo per pezzo se provi a separare diverse aree in cui ti trovi a scrivere grandi blocchi di if e applicare soluzioni a ciascuno di quei problemi minori.

Osserva tecniche come le regole di cui al Refactoring menzionato per trovare modi per suddividere grandi condizionali in blocchi gestibili: ad esempio, più classi con un'interfaccia comune possono sostituire un'istruzione case.

Anche uscire presto è di grande aiuto. Se si hanno condizioni di errore, toglierle di mezzo all'inizio della funzione lanciando un'eccezione o ritornando invece di lasciarle annidare.

Se dividi le tue condizioni in funzioni predicate, potrebbe essere più facile tenerne traccia. Inoltre, se riesci a inserirli in un modulo standard, potrebbe essere possibile inserirli in una struttura di dati costruita dinamicamente, anziché in un hardcoded.


2

Vorrei suggerire di utilizzare un motore di regole. In caso di Java, jBPM o Oracle BPM possono essere utili. I motori delle regole consentono sostanzialmente di configurare l'applicazione tramite XML.


+1 Ho usato Drools recentemente insieme a Mvel come lingua per esprimere le regole, ed è esattamente quello che stai cercando. Nonostante sia molto veloce.
Jalayn,

Drools è una buona scelta. Personalmente sto usando Oracle BPM in questo momento. C'è anche Feugo. Molti strumenti open source e di proprietà disponibili.
Sid,

2

Il problema non è ben risolto dalle "regole", descritte dal codice procedurale "if-then" o dalle numerose soluzioni di regole ideate per le applicazioni aziendali. L'apprendimento automatico offre una serie di meccanismi per modellare tali scenari.

Fondamentalmente, si deve formulare uno schema per la rappresentazione discreta dei fattori (ad es. Sole, vento, fonte di cibo, eventi improvvisi, ecc.) Che influenzano il "sistema" (cioè le mucche in un pascolo). Nonostante la convinzione fuorviante che si possa creare una rappresentazione funzionale veramente apprezzata, al contrario del discreto, nessun computer nel mondo reale (incluso il sistema nervoso umano) è basato sul valore reale o calcola sulla base di valori reali.

Una volta ottenuta la rappresentazione numerica per i fattori rilevanti, è possibile costruire uno dei numerosi modelli matematici. Vorrei suggerire un grafico bipartito in cui un insieme di nodi rappresenta le mucche e l'altro una parte dell'unità di pascolo. Una mucca in ogni caso occupa un'area unitaria di pascolo. Per ogni vacca esiste quindi un valore di utilità associato alla corrente e a tutte le altre unità di pascolo. Se il modello presuppone che la mucca cerchi di ottimizzare (qualunque sia tale mezzo per la mucca) il valore di utilità della sua unità di pascolo, le mucche si sposteranno da un'unità all'altra nel tentativo di ottimizzare.

Un automatismo cellulare funziona bene per l'esecuzione del modello. La matematica di fondo nel mondo della matematica stimata che motiva il movimento delle mucche è un modello a gradiente di campo. Le mucche si spostano da posizioni di valore di utilità inferiore percepito a posizioni di valore di utilità superiore percepito.

Se si inietta un cambiamento ambientale nel sistema, non si sposterà verso una soluzione allo stato stazionario di posizionamento della mucca. Diventerà anche un modello al quale potrebbero essere applicati aspetti della teoria dei giochi; non che ciò aggiungerebbe necessariamente molto a questo caso.

Il vantaggio qui è che le mucche da macello o l'acquisizione di nuove mucche possono essere prontamente gestite sottraendo e aggiungendo celle "vacche" al grafico bipartito, mentre il modello è in esecuzione.


1

Non penso che dovresti definire così tante dichiarazioni if-else. Dal mio punto di vista il tuo problema ha più componenti:

  • Dovrebbe essere asincrono o multithread, perché hai più mucche con personalità diverse, configurazione diversa. Ogni mucca si chiede in quale direzione andare prima della sua prossima mossa. Secondo me un codice di sincronizzazione è uno strumento scadente per questo problema.

  • La configurazione dell'albero decisionale cambia costantemente. Dipende dalla posizione della vacca reale, dal tempo, dal tempo, dal terreno, ecc ... Invece di costruire un complesso if-else tree, penso che dovremmo ridurre il problema a una rosa dei venti o una direzione - funzione del peso : Figura 1 figura 1 - direzione - funzioni di peso per alcune delle regole

    La mucca dovrebbe sempre andare nella direzione che ha il maggior peso totale. Quindi, invece di costruire un grande albero decisionale, puoi aggiungere una serie di regole (con direzione diversa - funzioni di peso) a ogni vacca, ed elaborare semplicemente il risultato ogni volta che chiedi la direzione. Puoi riconfigurare quelle regole ad ogni cambio di posizione, o con il passare del tempo, oppure puoi aggiungere questi dettagli come parametri, ogni regola dovrebbe ottenere. È una decisione di attuazione. Il modo più semplice per ottenere una direzione, aggiungere un semplice loop da 0 ° a 360 ° con 1 ° step. Dopodiché puoi contare il peso totale di ciascuna direzione 360 ​​ed eseguire una funzione max () per ottenere la direzione corretta.

  • Non hai necessariamente bisogno di una rete neurale per farlo, solo una classe per ogni regola, una classe per le mucche, forse per il terreno, ecc ... e una classe per lo scenario (ad esempio 3 mucche con regole diverse e 1 terreno specifico). figura 2 figura 2 - nodi e connessioni delle decisioni asincrone per le vacche

    • rosso per la direzione della messaggistica - mappa del peso attraverso le regole
    • blu per gli aggiornamenti di orientamento e posizione dopo il processo decisionale
    • verde per gli aggiornamenti di input dopo l'orientamento e l'aggiornamento della posizione
    • nero per ottenere input

    nota: probabilmente avrai bisogno di un framework di messaggistica per implementare qualcosa del genere

    Quindi, se fare mucche da apprendimento non fa parte del tuo problema, non hai bisogno di una rete neurale o di algoritmi genetici. Non sono un esperto di intelligenza artificiale, ma immagino che se vuoi adattare le tue mucche a quelle reali, allora puoi farlo semplicemente con un algoritmo genetico e il giusto set di regole. Se ho capito bene, hai bisogno di una popolazione di mucche con impostazioni casuali delle regole. Dopodiché puoi confrontare il comportamento delle mucche reali con il comportamento della tua popolazione modello e mantenere il 10% che percorre il percorso più vicino a quelli reali. Dopodiché puoi aggiungere nuovi vincoli di configurazione delle regole al tuo allevamento di vacche in base al 10% che hai tenuto e aggiungere nuove mucche casuali alla popolazione, e così via, fino a quando non ottieni una mucca modello che si comporta proprio come quelle reali ...


0

Aggiungerei che potrebbe essere il caso che se avessi davvero migliaia di regole IF ... THEN, potresti essere eccessivo. Per quello che vale, i colloqui di modellizzazione delle reti neurali a cui ho partecipato spesso iniziano con l'affermazione di come "con un semplice insieme di regole" possano generare comportamenti abbastanza complessi e ragionevolmente corrispondenti alla realtà (in quei casi, veri neuroni in azione). Quindi, sei sicurohai bisogno di migliaia di condizioni? Voglio dire, oltre a 4-5 aspetti del tempo, posizione delle fonti di cibo, eventi improvvisi, pastorizia e terreno, avrai davvero molte più variabili? Certo, se provassi a fare tutte le possibili permutazioni di combinazione di quelle condizioni, allora potresti facilmente avere molte migliaia di regole, ma questo non è l'approccio giusto. Forse un approccio di stile logico fuzzy in cui i vari fattori introducono un pregiudizio nella posizione di ogni mucca che si combina con una decisione complessiva ti permetterebbe di farlo in molte meno regole.

Concordo anche con tutti gli altri sul fatto che il set di regole dovrebbe essere separato dal flusso generale di codice, in modo da poterlo modificare facilmente senza cambiare il programma. Potresti persino inventare serie di regole in competizione e vedere come si comportano contro i dati reali sui movimenti delle mucche. Sembra divertente.


0

Sono stati menzionati i sistemi esperti, che sono un'area dell'IA. Per espandere un po 'su questi, leggere su motori di inferenza può aiutarti in questo. Una ricerca su Google potrebbe essere più utile: scrivere DSL è la parte facile, potresti farlo in modo banale con un parser come Gold Parser. La parte difficile deriva dalla costruzione del tuo albero delle decisioni e dalla sua efficiente esecuzione.

Molti sistemi medici utilizzano già questi motori, ad esempio il sito Web NHS Direct del Regno Unito .

Se sei un .NET, Infer.NET potrebbe essere utile per te.


0

Dal momento che guardi il movimento della mucca, sono bloccati in una direzione a 360 gradi (le mucche non possono volare.) Hai anche un tasso di viaggiare. Questo può essere definito come un vettore.

Ora come gestisci cose come la posizione del sole, la pendenza della collina, il rumore forte?

Ciascuno dei gradi sarebbe una variabile che indica il desiderio di andare in quella direzione. Di 'un ramoscello che scatta a destra della mucca a 90 gradi (supponendo che la mucca sia rivolta a 0 gradi). Il desiderio di andare a destra diminuirà e il desiderio di andare a 270 (a sinistra) aumenterà. Passa attraverso tutti gli stimoli aggiungendo o sottraendo la loro influenza sul desiderio delle mucche di andare in una direzione. Una volta applicati tutti gli stimoli, la mucca andrà nella direzione del più alto desiderio.

Puoi anche applicare gradienti in modo che gli stimoli non debbano essere binari. Ad esempio una collina non è diritta in una direzione. Forse la mucca si trova in una valle o su una strada su una collina dove la sua piana è dritta, a 45 * in leggera salita a 90 * in leggera discesa. A 180 * ripida collina.

È quindi possibile regolare il peso di un evento e la sua direzione di influenza. Piuttosto quindi un elenco di se poi, hai un test alla ricerca del massimo. Inoltre, quando vuoi aggiungere uno stimolo, puoi semplicemente applicarlo prima del test e non devi occuparti di aggiungere sempre più complessità.

Piuttosto quindi dire che la mucca andrà in qualsiasi direzione a 360 ° semplicemente scomponendola in 36 direzioni. Ciascuno è di 10 gradi

Piuttosto quindi dire che la mucca andrà in qualsiasi direzione a 360 ° semplicemente scomponendola in 36 direzioni. Ciascuno è di 10 gradi. A seconda di quanto devi essere specifico.


-2

Usa OOP. Che ne dici di creare un gruppo di classi che gestiscono le condizioni di base ed eseguire metodi casuali per simulare ciò che stai facendo.

Chiedi a un programmatore di aiutarti.

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.  */
}

Perché questa è l'ultima risposta. Arriva al punto, che è che migliaia di istruzioni if ​​else sono semplicemente ora il modo di progettare un programma.
wfbarksdale,

1
Perché raccomandare " Usa OOP. Chiedi a un programmatore di aiutarti " vale lo stesso che dare il consiglio " Fai più telefonate! " Quando ti viene chiesto " Come posso quadruplicare le mie vendite? ". Non è strettamente sbagliato, ma non aiuta molto.
JensG,

2
Ho annullato il voto, perché questa è una cattiva risposta. tecnicamente; la tua risposta ha poco a che fare con OOP. Una classe chiamata COW_METHODSsembra essere nient'altro che una raccolta di metodi vagamente correlati. Dov'è la separazione delle preoccupazioni? In relazione alla domanda, in che modo aiuta chi chiede?
oɔɯǝɹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.