Jak zarządzać tysiącami zasad IF… THEN… ELSE?


214

Zastanawiam się nad stworzeniem aplikacji, która w swej istocie składałaby się z tysięcy instrukcji if ... then ... else. Celem aplikacji jest przewidzenie, w jaki sposób krowy poruszają się w dowolnym krajobrazie. Wpływają na nie takie rzeczy jak słońce, wiatr, źródło pożywienia, nagłe wydarzenia itp.

Jak można zarządzać taką aplikacją? Wyobrażam sobie, że po kilkuset instrukcjach IF byłoby tak samo dobrze, jak nieprzewidywalnie, jak program zareagowałby, a debugowanie tego, co doprowadziło do pewnej reakcji, oznaczałoby, że za każdym razem trzeba byłoby przejść przez całe drzewo instrukcji IF.

Przeczytałem trochę o silnikach reguł, ale nie wiem, jak poradzą sobie z tą złożonością.


22
Musisz rzucić okiem na Programowanie DSL: en.wikipedia.org/wiki/Domain-specific_language Ponadto można również stworzyć silnik meta reguł oparty na danych. Np. Można wygenerować modele na podstawie danych (np. Eksploracja danych KDD)
Darknight

14
google dla „systemu eksperckiego” i „rete net”; powodzenia.
Steven A. Lowe,

9
Przenieś zakodowane na stałe instrukcje if / then z kodu źródłowego do danych zewnętrznych, które napędzają symulację.
Kwebble,

6
Przekręciłem niektóre wartości w pliku tekstowym i użyłem pętli, aby przejść przez HashMap zawierający nazwy.
James P.

2
David - na programistach pytania są konwertowane na CW, gdy opublikowanych jest ponad 15 odpowiedzi. Nie możemy kontrolować, kto opublikuje 16. odpowiedź.
ChrisF

Odpowiedzi:


73

Logiczny język programowania Prolog może być tym, czego szukasz. Twoje stwierdzenie problemu nie jest wystarczająco szczegółowe, aby ocenić, czy jest dobrze dopasowane, ale jest raczej podobne do tego, co mówisz.

Program Prolog składa się z zastosowanych faktów i zasad. Oto prosta przykładowa reguła, która mówi: „Krowa przenosi się na miejsce, jeśli jest głodna, aw nowej lokalizacji jest więcej jedzenia niż w starej lokalizacji”:

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

Wszystkie wielkie litery to zmienne, których wartości nie znasz. Prolog próbuje znaleźć wartości dla tych zmiennych, które spełniają wszystkie warunki. Proces ten odbywa się za pomocą potężnego algorytmu zwanego unifikacją, który jest sercem Prologa i podobnych logicznych środowisk programistycznych.

Oprócz zasad udostępniana jest baza faktów. Prostym przykładem, który działa z powyższymi regułami, może być coś takiego:

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

Zauważ, że white_cow i pastwiska itp. Nie są pisane wielkimi literami. Nie są zmiennymi, są atomami.

Na koniec zadaj pytanie i zapytaj, co się stanie.

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

Pierwsze zapytanie dotyczy miejsca, w którym porusza się biała krowa. Biorąc pod uwagę powyższe zasady i fakty, odpowiedź brzmi: nie. Można to interpretować jako „nie wiem” lub „nie porusza się” w zależności od tego, czego chcesz.

Drugie zapytanie dotyczy miejsca, w którym porusza się czarna krowa. Przenosi się na pastwisko, aby zjeść.

Ostatnie zapytanie dotyczy miejsca, w którym poruszają się wszystkie krowy. W rezultacie otrzymujesz wszystkie możliwe (Krowa, Miejsce Przeznaczenia), które mają sens. W takim przypadku czarny byk przenosi się na pastwisko zgodnie z oczekiwaniami. Jednak wściekły byk ma dwie możliwości, które spełniają zasady, albo może przenieść się na pastwisko lub do stodoły.

Uwaga: minęły lata, odkąd ostatnio pisałem Prolog, wszystkie przykłady mogą nie być poprawne pod względem składniowym, ale pomysł powinien być poprawny.


10
-1: Nie sądzę, że Prolog może być właściwą odpowiedzią. Tak, może być łatwo uzyskać reguły if-else w Prologu. Ale na pewno będziesz musiał zrobić coś innego. I bez względu na to, co to jest (IO; GUI, tworzenie stron internetowych ...) będzie to problem z Prologiem.
Martin Thoma,

4
Sprawdź learnprolognow.com A osadzenie prologu w innym języku jest o wiele łatwiejsze niż kiedyś
Zachary K

@ZacharyK: Link jest uszkodzony.
RenniePet

@MartinThoma: czy możesz wyjaśnić swój komentarz? Główne problemy z Prolog IMHO to brak 1. deklaratywnego sposobu kontrolowania wyszukiwania i 2. pisania. Ale jeśli twoja aplikacja nie zależy w dużym stopniu od tych dwóch, to nie widzę a priori problemu z użyciem Prologa tutaj
SN

139

Rozwiązując problem sieciowy , możesz stworzyć silnik reguł, w którym każda konkretna reguła jest kodowana niezależnie. Kolejnym udoskonaleniem tego byłoby utworzenie języka specyficznego dla domeny (DSL) w celu utworzenia reguł, jednak sama DSL przesuwa problem tylko z jednej bazy kodu (głównej) na inną (DSL). Bez struktury DSL nie poradzi sobie lepiej niż język ojczysty (Java, C # itp.), Więc wrócimy do niego po znalezieniu ulepszonego podejścia strukturalnego.

Podstawową kwestią jest to, że masz problem z modelowaniem. Ilekroć napotkasz takie sytuacje kombinatoryczne, jest to wyraźny znak, że twoja abstrakcja modelu opisująca sytuację jest zbyt gruba. Najprawdopodobniej łączysz elementy, które powinny należeć do różnych modeli w jednym obiekcie.

Jeśli nadal będziesz rozkładać swój model, ostatecznie całkowicie rozpuścisz ten efekt kombinatoryczny. Jednak idąc tą ścieżką łatwo jest zgubić się w projekcie, tworząc jeszcze większy bałagan, perfekcjonizm tutaj niekoniecznie jest twoim przyjacielem.

Maszyny stanów skończonych i silniki reguł są tylko przykładem tego, jak można rozwiązać ten problem i uczynić go łatwiejszym do zarządzania. Główną ideą tutaj jest to, że dobrym sposobem na pozbycie się takiego problemu kombinatorycznego jest często stworzenie projektu i powtórzenie go ad-nudności w zagnieżdżonych poziomach abstrakcji, aż system osiągnie zadowalające wyniki. Podobnie jak fraktale są używane do tworzenia skomplikowanych wzorów. Zasady pozostają takie same, bez względu na to, czy patrzysz na swój system za pomocą mikroskopu, czy z lotu ptaka.

Przykład zastosowania tego w swojej domenie.

Próbujesz modelować ruch krów w terenie. Chociaż w twoim pytaniu brakuje szczegółów, sądzę, że twoja duża liczba ifs zawiera fragment decyzji, na przykład, if cow.isStanding then cow.canRun = trueale utkniesz w trakcie dodawania szczegółów terenu. Dlatego dla każdego działania, które chcesz podjąć, musisz sprawdzić wszystkie aspekty, które możesz wymyślić, i powtórzyć te weryfikacje dla następnego możliwego działania.

Najpierw potrzebujemy naszego powtarzalnego projektu, którym w tym przypadku będzie FSM do modelowania zmieniających się stanów symulacji. Pierwszą rzeczą, którą bym zrobił, to zaimplementować referencyjny FSM, definiujący interfejs stanu, interfejs przejścia i być może kontekst przejściaktóry może zawierać wspólne informacje, które zostaną udostępnione pozostałym dwóm. Podstawowa implementacja FSM będzie się przełączać z jednego przejścia na drugie, niezależnie od kontekstu, tutaj pojawia się silnik reguł. Silnik reguł dokładnie określa warunki, które należy spełnić, aby przejście miało nastąpić. Tutaj silnik reguł może być tak prosty jak lista reguł, z których każda ma funkcję oceny zwracającą wartość logiczną. Aby sprawdzić, czy przejście powinno nastąpić, dokonujemy iteracji listy reguł, a jeśli którakolwiek z nich ma wartość false, przejście nie ma miejsca. Samo przejście będzie zawierało kod behawioralny służący do modyfikacji bieżącego stanu FSM (i innych możliwych zadań).

Teraz, jeśli zacznę implementować symulację jako pojedynczy duży FSM na poziomie BOGA, otrzymam DUŻO możliwych stanów, przejść itp. Bałagan jeśli-inaczej wygląda na naprawiony, ale tak naprawdę rozprzestrzenia się: każdy IF jest teraz reguła, która wykonuje test pod kątem konkretnej informacji kontekstu (która w tym momencie zawiera prawie wszystko), a każda treść JEŻELI znajduje się gdzieś w kodzie przejścia.

Wprowadź podział fraktali: pierwszym krokiem byłoby utworzenie FSM dla każdej krowy, w której stany są stanami wewnętrznymi krowy (stojąca, biegająca, chodząca, pasąca się itp.), A środowisko będzie miało wpływ na przejścia między nimi. Możliwe, że wykres nie jest kompletny, na przykład wypas jest dostępny tylko ze stanu stojącego, wszelkie inne przejścia są odrzucane, ponieważ po prostu nie ma go w modelu. Tutaj skutecznie dzielisz dane na dwa różne modele, krowę i teren. Każdy z własnym zestawem właściwości. Podział ten pozwoli uprościć ogólny projekt silnika. Teraz zamiast jednego silnika reguł, który decyduje o wszystkim, masz wiele, prostszych mechanizmów reguł (po jednym dla każdej przejścia), które decydują o bardzo szczegółowych szczegółach.

Ponieważ ponownie używam tego samego kodu dla FSM, jest to w zasadzie konfiguracja FSM. Pamiętasz, jak wspominaliśmy wcześniej o DSL? W tym miejscu DSL może wiele zdziałać, jeśli masz dużo reguł i przejść do napisania.

Schodzę głębiej

Teraz BÓG nie musi już radzić sobie z całą złożonością zarządzania wewnętrznymi stanami krowy, ale możemy to zrobić dalej. Na przykład zarządzanie terenem jest nadal bardzo skomplikowane. Tutaj decydujesz, gdzie wystarczy rozbicie. Jeśli na przykład w swoim BOGU skończysz zarządzanie dynamiką terenu (długa trawa, błoto, suche błoto, krótka trawa itp.), Możemy powtórzyć ten sam wzór. Nic nie stoi na przeszkodzie, aby wprowadzić taką logikę w sam teren poprzez wyodrębnienie wszystkich stanów terenu (długa trawa, krótka trawa, błotnista, sucha itp.) Do nowego terenu FSM z przejściami między stanami i być może prostymi regułami. Na przykład, aby przejść do stanu błotnistego, silnik reguł powinien sprawdzić kontekst w celu znalezienia płynów, w przeciwnym razie nie jest to możliwe. Teraz BÓG stał się jeszcze prostszy.

Możesz uzupełnić system FSM, czyniąc go autonomicznym i nadając każdemu wątek. Ten ostatni krok nie jest konieczny, ale umożliwia dynamiczną zmianę interakcji systemu poprzez dostosowanie sposobu delegowania decyzji (uruchomienie specjalistycznego FSM lub po prostu przywrócenie wcześniej określonego stanu).

Pamiętasz, jak wspomnieliśmy, że przejścia mogą również wykonywać „inne możliwe zadania”? Zbadajmy to, dodając możliwość komunikacji między różnymi modelami (FSM). Możesz zdefiniować zestaw zdarzeń i zezwolić każdemu FSM na zarejestrowanie odbiornika tych zdarzeń. Tak więc, jeśli na przykład krowa wchodzi na heks terenu, heks może zarejestrować słuchaczy pod kątem zmian przejścia. Tutaj staje się to nieco trudne, ponieważ każdy FSM jest wdrażany na bardzo wysokim poziomie bez wiedzy o konkretnej domenie, w której się znajduje. Możesz to jednak osiągnąć poprzez opublikowanie przez krowę listy zdarzeń, a komórka może się zarejestrować, jeśli zobaczy zdarzenia, na które może zareagować. Dobra hierarchia rodziny wydarzeń tutaj jest dobrą inwestycją.

Możesz pchać jeszcze głębiej, modelując poziomy składników odżywczych i cykl wzrostu trawy, za pomocą ... zgadłeś ... FSM trawy osadzonej we własnym modelu łaty terenu.

Jeśli popchniecie tę ideę wystarczająco daleko, BÓG ma bardzo niewiele do zrobienia, ponieważ wszystkie aspekty są właściwie samozarządzane, uwalniając czas na wydawanie na bardziej pobożne rzeczy.

Podsumować

Jak wspomniano powyżej, FSM nie jest tutaj rozwiązaniem, a jedynie środkiem do zilustrowania, że ​​rozwiązania takiego problemu nie ma w kodzie, powiedzmy, w jaki sposób modelujesz swój problem. Najprawdopodobniej istnieją inne rozwiązania, które są możliwe i najprawdopodobniej znacznie lepsze niż moja propozycja FSM. Jednak podejście „fraktali” pozostaje dobrym sposobem radzenia sobie z tą trudnością. Jeśli zrobisz to poprawnie, możesz dynamicznie alokować głębsze poziomy tam, gdzie ma to znaczenie, jednocześnie dając prostsze modele tam, gdzie ma to mniejsze znaczenie. Możesz kolejkować zmiany i stosować je, gdy zasoby staną się bardziej dostępne. W sekwencji akcji może nie być aż tak ważne obliczenie transferu składników pokarmowych z krowy na trawę. Możesz jednak zarejestrować te przejścia i zastosować zmiany w późniejszym czasie lub w przybliżeniu z wyuczonym odgadnięciem, po prostu zastępując mechanizmy reguł lub ewentualnie zastępując implementację FSM prostszą naiwną wersją dla elementów, które nie znajdują się w bezpośrednim polu zainteresowanie (ta krowa na drugim końcu pola), aby umożliwić bardziej szczegółowe interakcje, aby uzyskać koncentrację i większy udział zasobów. Wszystko to bez ponownego przeglądania systemu jako całości; ponieważ każda część jest dobrze odizolowana, łatwiej jest stworzyć zastępczą wymianę ograniczającą lub rozszerzającą głębokość modelu. Korzystając ze standardowego projektu, możesz na tym oprzeć i zmaksymalizować inwestycje w narzędzia ad-hoc, takie jak DSL, w celu zdefiniowania reguł lub standardowego słownictwa dla wydarzeń, ponownie zaczynając od bardzo wysokiego poziomu i dodając udoskonalenia w razie potrzeby. ponieważ każda część jest dobrze odizolowana, łatwiej jest stworzyć zastępczą wymianę ograniczającą lub rozszerzającą głębokość modelu. Korzystając ze standardowego projektu, możesz na tym oprzeć i zmaksymalizować inwestycje w narzędzia ad-hoc, takie jak DSL, w celu zdefiniowania reguł lub standardowego słownictwa dla wydarzeń, ponownie zaczynając od bardzo wysokiego poziomu i dodając udoskonalenia w razie potrzeby. ponieważ każda część jest dobrze odizolowana, łatwiej jest stworzyć zastępczą wymianę ograniczającą lub rozszerzającą głębokość modelu. Korzystając ze standardowego projektu, możesz na tym oprzeć i zmaksymalizować inwestycje w narzędzia ad-hoc, takie jak DSL, w celu zdefiniowania reguł lub standardowego słownictwa dla wydarzeń, ponownie zaczynając od bardzo wysokiego poziomu i dodając udoskonalenia w razie potrzeby.

Podałbym przykład kodu, ale to wszystko, co mogę teraz zrobić.


1
Przyjąłem tę odpowiedź, ponieważ jest to rząd wielkości lepszy w wyjaśnianiu rozwiązania niż inne. Mogę jednak zmienić przyjętą odpowiedź, jeśli pojawi się lepsza. Twoje rozwiązanie wydaje się także na tyle radykalne, by coś zmienić. Nadal jednak mam problemy ze zrozumieniem, jak zdefiniować zasady interakcji między różnymi modelami. Czy mógłbyś podać przykład tego?
David

-1 Nie rozumiem, dlaczego nie można tego po prostu rozwiązać za pomocą drzewa decyzyjnego? (w połączeniu z DSL, która pobiera model i zamienia go w kod wykonywalny)?
Darknight

14
BÓG vs FSM?
John Cromartie,

1
Drzewa decyzyjne i silniki reguł stosowane są właśnie w przypadkach, w których modelowanie omawianych aspektów nie ma wewnętrznej wartości, ponieważ są jedynie środkiem do zakończenia obliczeń. Cały czas widzisz to w oprogramowaniu opieki zdrowotnej. Biorąc to pod uwagę, jeśli próbujesz modelować rzeczywiste zachowanie, powinieneś to zrobić. Istnieje mnóstwo przypadków, w których jedyna logika znaleziona w problemie jest wynikiem tysięcy, jeśli to wtedy to nieskończone. I to jest ważne, dlatego mamy narzędzia, aby sobie z tym poradzić.
usunięte_user

1
Okazało się to bardzo udane w świecie programowania gier; znacznie szybciej i łatwiej jest zmienić regułę lub właściwość i pozwolić na pojawienie się zachowania, a następnie zbadać wartość, aby zdecydować, jak ją zastosować.
Ben Leggiero,

89

Wygląda na to, że wszystkie te instrukcje warunkowe, o których mówisz, powinny być danymi konfigurującymi program, a nie częścią samego programu. Jeśli możesz potraktować je w ten sposób, będziesz mógł dowolnie modyfikować sposób działania programu, zmieniając jego konfigurację zamiast modyfikować kod i rekompilować za każdym razem, gdy będziesz chciał ulepszyć swój model.

Istnieje wiele różnych sposobów modelowania prawdziwego świata, w zależności od charakteru problemu. Różne warunki mogą stać się regułami lub ograniczeniami stosowanymi w symulacji. Zamiast kodu, który wygląda następująco:

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

zamiast tego możesz mieć kod wyglądający następująco:

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

Lub, jeśli potrafisz opracować program liniowy, który modeluje zachowanie krów na podstawie szeregu danych wejściowych, każde ograniczenie może stać się linią w układzie równań. Następnie możesz przekształcić to w model Markowa, który możesz iterować.

Trudno powiedzieć, jakie jest właściwe podejście do twojej sytuacji, ale myślę, że będziesz miał o wiele łatwiej, jeśli weźmiesz pod uwagę ograniczenia jako dane wejściowe do programu, a nie kod.


4
Opisz jak „cow.apply (reguła);” działa z plikami konfiguracyjnymi?
Kromster

8
@Krom, trudno powiedzieć konkretnie, nie wiedząc, o jakim systemie mówimy. Chodzi mi o to, aby traktować tysiące warunków jako dane wejściowe do programu, abyś nie musiał pisać kodu dla każdego z nich i mógł zmieniać warunki bez zmiany programu. Ale tak, jeśli warunki można traktować jako dane, należy je przechowywać oddzielnie od programu w jakimś dokumencie lub pliku konfiguracyjnym.
Caleb

2
@Krom - Prosty. Przeczytasz regułę, a następnie zastosujesz ją do danej krowy.
Ramhound

5
Przenoszenie kodu do plików konfiguracyjnych nie zawsze jest dobrym podejściem. Trudno jest debugować magię.
Ricky Clarkson

44

Nikt o tym nie wspominał, więc pomyślałem, że powiedziałbym to wprost:

Tysiące reguł „Jeśli .. To… jeszcze” jest oznaką źle zaprojektowanej aplikacji.

Chociaż reprezentacja danych dla konkretnej domeny może wyglądać tak, jak te reguły, to czy jesteś absolutnie pewien, że twoja implementacja powinna przypominać reprezentację dla konkretnej domeny?


18
Niekoniecznie prawda. Istnieją problemy, które można rozwiązać tylko poprzez ogromne drzewa decyzyjne. Ale oczywiście rozwiązanie dla tych, które składają się z dosłownego drzewa „jeśli-to-jeszcze”, jest źle zaprojektowane. Istnieją o wiele bardziej elastyczne i łatwe w utrzymaniu sposoby realizacji tego.
SF.

43
Myślałem, że o to właśnie chodzi. OP ma specyficzny dla swojej domeny problem, który w naiwnej implementacji wymagałby tysięcy, gdyby ... wtedy ... inaczej. Miał intuicję, że to będzie kłopotliwe, i zapytał tę społeczność o lepsze sposoby na zrobienie tego. Sam fakt, że pytanie zostało zadane, jest dobrym śpiewem, że zostało to już zrozumiane, twoja odpowiedź, choć poprawna, nie pomaga w żaden sposób na pytanie.
Newtopian

@Newtopian Zaawansowany użytkownik lub programista zrozumie to i uzna to za oczywiste. Naiwny użytkownik lub programista może jednak nie zdawać sobie z tego sprawy. Świadomie stwierdziłem, co większość ludzi uważa za oczywiste - potwierdziłem, że PO ma rację, zakładając, że byłoby to problematyczne i zdecydowanie nie powinien iść w parze z natychmiastowym lub naiwnym wdrożeniem.
blueberryfields

Zgadzam się, możesz zastąpić polimorfizmem, a także DI. jeśli masz zyliony jeśli jeszcze, twój projekt jest bardzo zły.
DarthVader

17

Proszę używać języków oprogramowania / komputera odpowiednich do tego zadania. Matlab jest bardzo często używany do modelowania złożonych systemów, w których można dosłownie mieć tysiące warunków. Nie używając klauzul if / then / else, ale poprzez analizę numeryczną. R jest językiem komputerowym typu open source, który jest wypełniony narzędziami i pakietami, aby zrobić to samo. Oznacza to jednak, że musisz również przekształcić swój model bardziej matematycznie, abyś mógł uwzględnić zarówno główne wpływy, jak i interakcje między wpływami w modelach.

Jeśli jeszcze tego nie zrobiłeś, przejdź kurs dotyczący modelowania i symulacji. Ostatnią rzeczą, którą powinieneś zrobić, jest rozważenie napisania takiego modelu pod względem, jeśli - to - jeszcze. Mamy łańcuchy Monte Carlo Markov, maszyny wektorów wsparcia, sieci neuronowe, analizę zmiennych utajonych ... Nie rzucaj się 100 lat wstecz, ignorując bogactwo dostępnych narzędzi do modelowania.


Dziwi mnie, jak mało uwagi poświęcono temu pytaniu. Analiza numeryczna i modelowanie to sedno maszyny if-else. Jednak cierpi z powodu fałszywych wyników pozytywnych, które mogą nie być tolerowane, jeśli wniosek wymaga ścisłego przestrzegania zasad. (Myśl bankowość)
Arun Jose

13

Silniki reguł mogą pomóc, ponieważ jeśli istnieje tak wiele reguł typu „jeśli / to”, pomocne może być umieszczenie ich wszystkich w jednym miejscu poza programem, gdzie użytkownicy mogą je edytować bez konieczności znajomości języka programowania. Mogą być również dostępne narzędzia do wizualizacji.

Możesz także przyjrzeć się rozwiązaniom programowania logicznego (np. Prolog). Możesz szybko zmodyfikować listę instrukcji if / then i sprawić, by wyglądała na to, czy jakakolwiek kombinacja danych wejściowych doprowadziłaby do pewnych wyników itp. Może się również zdarzyć, że będzie czystsza w logice predykatów pierwszego rzędu niż jako kod proceduralny (lub jako kod obiektowy).


11

Nagle mnie olśniło:

Musisz użyć drzewa decyzyjnego (algorytm ID3).

Jest bardzo prawdopodobne, że ktoś zaimplementował to w twoim języku. Jeśli nie, możesz przenieść istniejącą bibliotekę


Idź z pomysłem DSL podanym powyżej. Spróbuj dowiedzieć się, jak wyodrębnić problem do jakiejś formy symbolicznej algebry, a następnie zaimplementuj to.
Zachary K


9

Każda duża aplikacja zawiera tysiące if-then-elseinstrukcji, nie licząc innych kontroli przepływu, a aplikacje te są nadal debugowane i utrzymywane, pomimo ich złożoności.

Ponadto liczba instrukcji nie powoduje, że przepływ jest nieprzewidywalny . Programowanie asynchroniczne działa. Jeśli użyjesz algorytmów deterministycznych synchronicznie, będziesz mieć w 100% przewidywalne zachowanie za każdym razem.

Prawdopodobnie powinieneś lepiej wyjaśnić, co próbujesz zrobić w przypadku przepełnienia stosu lub przeglądu kodu , aby ludzie mogli zasugerować ci dokładne techniki refaktoryzacji . Możesz także zadać bardziej precyzyjne pytania, na przykład „Jak uniknąć zagnieżdżania zbyt dużej ifliczby instrukcji <dany fragment kodu>”.


1
Większość aplikacji ma 2-3 poziomy zagnieżdżenia i warunki 1-liniowe. Co z problemem, który wymaga drzewa decyzyjnego zagnieżdżonego o 50 poziomów w dół, a wiele warunków jest logicznymi związkami złożonymi z 30 lub więcej zmiennych?
SF.

Chociaż „Każda duża aplikacja ...” jest z pewnością prawdą, jest całkiem jasne, że OP mówi o długich sekwencjach wyrażeń warunkowych, które zasadniczo tworzą reguły w modelu. Ogromne zagnieżdżone grupy ifinstrukcji szybko stają się niewygodne, więc wymagane jest lepsze podejście.
Caleb

@Caleb: masz rację, to jasne, teraz , z precyzyjnym przykład na początku pytanie. Dopiero po zredagowaniu pytania napisałem swoją odpowiedź. To wyjaśnia faktyczną niespójność mojej i dwóch innych odpowiedzi opublikowanych w tym samym czasie.
Arseni Mourzenko

2

Spraw, aby Twoja aplikacja była łatwa do zarządzania, projektując ją dobrze. Zaprojektuj swoją aplikację, dzieląc różne logiki biznesowe na osobne klasy / moduły. Napisz testy jednostkowe, które testują każdą z tych klas / modułów osobno. Ma to kluczowe znaczenie i pomoże zapewnić, że logika biznesowa jest wdrażana zgodnie z oczekiwaniami.


2

Prawdopodobnie nie będzie jednego sposobu na rozwiązanie problemu, ale możesz zarządzać złożonością tego po kawałku, jeśli spróbujesz wydzielić różne obszary, w których piszesz duże bloki instrukcji if i zastosujesz rozwiązania do każdego z tych mniejszych problemów.

Spójrz na techniki takie jak reguły omówione w Refaktoryzacji, aby dowiedzieć się, jak podzielić duże warunki warunkowe na porcje do zarządzania - na przykład wiele klas ze wspólnym interfejsem może zastąpić instrukcję case.

Wyjście wcześniej również jest bardzo pomocne. Jeśli występują warunki błędu, usuń je z drogi na początku funkcji, zgłaszając wyjątek lub zwracając zamiast pozwalać im się zagnieżdżać.

Jeśli podzielisz warunki na funkcje predykatów, łatwiej będzie je śledzić. Ponadto, jeśli uda Ci się wprowadzić je do standardowej postaci, możliwe, że uda się uzyskać je w strukturze danych zbudowanej dynamicznie, a nie na sztywno.


2

Sugeruję użycie silnika reguł. W przypadku Javy przydatne może być jBPM lub Oracle BPM. Mechanizmy reguł pozwalają zasadniczo skonfigurować aplikację za pomocą XML.


+1 Ostatnio używałem Drools wraz z Mvel jako językiem do wyrażania reguł i to jest dokładnie to, czego szukasz. Pomimo tego, że jest bardzo szybki.
Jalayn

Drools to dobry wybór. Obecnie osobiście korzystam z Oracle BPM. Jest też Feugo. Dostępnych jest wiele narzędzi typu open source i odpowiednich narzędzi.
Sid

2

Problem nie jest dobrze rozwiązany za pomocą „reguł”, czy to opisanych przez kod proceduralny „jeśli-to”, czy też liczne rozwiązania reguł opracowane dla aplikacji biznesowych. Uczenie maszynowe zapewnia szereg mechanizmów modelowania takich scenariuszy.

Zasadniczo należy sformułować pewien schemat opisujący czynniki (np. Słońce, wiatr, źródło pożywienia, nagłe zdarzenia itp.) Wpływające na „system” (tj. Krowy na pastwisku). Niezależnie od błędnego przekonania, że ​​można stworzyć funkcjonalną reprezentację o wartościowej wartości, w przeciwieństwie do dyskretnej, żaden komputer w prawdziwym świecie (w tym ludzki układ nerwowy) nie jest oparty na wartościach rzeczywistych lub obliczany na podstawie rzeczywistych wartości.

Po uzyskaniu reprezentacji numerycznej dla odpowiednich czynników można skonstruować dowolny z kilku modeli matematycznych. Sugerowałbym dwustronny wykres, w którym jeden zestaw węzłów reprezentuje krowy, a drugi jakiś jednostkowy obszar pastwiska. Krowa w każdym przypadku zajmuje część obszaru pastwiska. Dla każdej krowy istnieje wartość użyteczna związana z bieżącą i wszystkimi innymi jednostkami pastwisk. Jeśli model zakłada, że ​​krowa dąży do optymalizacji (niezależnie od tego, co to oznacza dla krowy) wartości użytkowej swojej jednostki pastwiska, wówczas krowy będą się przemieszczać z jednostki do jednostki w celu optymalizacji.

Automatyzacja komórkowa działa dobrze przy wykonywaniu modelu. Matematyka w świecie matematyki motywującym ruch krowy w rzeczywistości stanowi model gradientu pola. Krowy przechodzą z pozycji postrzeganej niższej wartości użytkowej do pozycji postrzeganej wyższej wartości użytkowej.

Jeśli ktoś wstrzykuje zmiany środowiskowe do systemu, wówczas nie przejdzie do stabilnego rozwiązania pozycjonowania krów. Stanie się również modelem, do którego można by zastosować aspekty teorii gier; nie to, że niekoniecznie dodałoby wiele do tego przypadku.

Zaletą jest to, że krowy rzeźne lub pozyskiwanie nowych krów można łatwo zarządzać, odejmując i dodając komórki „krowy” do dwustronnego wykresu, gdy model jest uruchomiony.


1

Nie sądzę, że powinieneś zdefiniować tak wiele instrukcji if-else. Z mojego punktu widzenia twój problem ma wiele elementów:

  • Powinien być asynchroniczny lub wielowątkowy, ponieważ masz wiele krów o różnych osobowościach i różnych konfiguracjach. Każda krowa pyta się, w którą stronę pójść, przed kolejnym ruchem. Moim zdaniem kod synchronizacji jest słabym narzędziem do tego problemu.

  • Konfiguracja drzewa decyzyjnego stale się zmienia. Zależy to od położenia faktycznej krowy, pogody, czasu, terenu itp. Zamiast budować złożone drzewo, jeśli nie, myślę, że powinniśmy zredukować problem do róży wiatrów lub kierunku - funkcja wagi : ryc.1 rysunek 1 - funkcje kierunku - waga dla niektórych reguł

    Krowa powinna zawsze iść w kierunku o największej wadze. Zamiast budować duże drzewo decyzyjne, możesz dodać zestaw reguł (z różnymi funkcjami kierunku i wagi) do każdej krowy i po prostu przetworzyć wynik za każdym razem, gdy pytasz o kierunek. Możesz zmienić te reguły przy każdej zmianie pozycji lub z upływem czasu, lub możesz dodać te szczegóły jako parametry, które każda reguła powinna otrzymać. Jest to decyzja wdrożeniowa. Najprostszym sposobem uzyskania kierunku jest dodanie prostej pętli od 0 ° do 360 ° z krokiem 1 °. Następnie możesz policzyć wagę sumaryczną każdego kierunku 360 i przejść przez funkcję max (), aby uzyskać właściwy kierunek.

  • Nie musisz do tego potrzebować sieci neuronowej, tylko jedna klasa dla każdej reguły, jedna klasa dla krów, może dla terenu itp. ... i jedna klasa dla scenariusza (na przykład 3 krowy z różnymi regułami i 1 określony teren). Rysunek 2 rysunek 2 - węzły i połączenia decyzyjne aplikacji krowy

    • czerwony dla kierunku wysyłania wiadomości - mapa wagi według zasad
    • niebieski dla orientacji i aktualizacji pozycji po podjęciu decyzji
    • zielony dla aktualizacji danych wejściowych po aktualizacji orientacji i pozycji
    • czarny dla uzyskania danych wejściowych

    Uwaga: prawdopodobnie potrzebujesz struktury przesyłania wiadomości, aby zaimplementować coś takiego

    Więc jeśli tworzenie uczących się krów nie jest częścią twojego problemu, nie potrzebujesz sieci neuronowej ani algorytmów genetycznych. Nie jestem ekspertem od sztucznej inteligencji, ale myślę, że jeśli chcesz dostosować swoje krowy do prawdziwych, możesz to zrobić po prostu za pomocą algorytmu genetycznego i odpowiedniego zestawu reguł. Jeśli dobrze rozumiem, potrzebujesz populacji krów z losowymi ustawieniami reguł. Następnie możesz porównać zachowanie prawdziwych krów z zachowaniem populacji modelowej i zachować 10%, które podążają ścieżką najbliższą prawdziwym. Następnie możesz dodać nowe ograniczenia konfiguracji reguł do fabryki krów w oparciu o 10%, które utrzymałeś, i dodać nowe losowe krowy do populacji, i tak dalej, dopóki nie otrzymasz modelowej krowy, która zachowuje się tak jak prawdziwe ...


0

Dodałbym, że może być tak, że jeśli naprawdę masz tysiące JEŻELI ... WTEDY reguły, możesz być zbyt zawężający. Co warte jest tego, rozmowy na temat modelowania sieci neuronowych, w których często uczestniczyłem, zaczynają się od stwierdzenia, że ​​„prostym zestawem reguł” mogą generować dość złożone i racjonalnie odpowiadające rzeczywistości zachowanie (w tych przypadkach prawdziwe neurony w akcji). Jesteś pewien?potrzebujesz tysięcy warunków? Mam na myśli, poza 4-5 aspektami pogody, lokalizacją źródeł żywności, nagłymi zdarzeniami, stadem i terenem, czy naprawdę będziesz mieć wiele innych zmiennych? Jasne, że jeśli spróbujesz wykonać wszystkie możliwe kombinacje łączenia tych warunków, możesz łatwo mieć wiele tysięcy reguł, ale to nie jest właściwe podejście. Być może podejście oparte na logice rozmytej, w którym różne czynniki wprowadzają błąd w lokalizacji każdej krowy w połączeniu z ogólną decyzją, pozwoliłoby ci to zrobić na znacznie mniejszej liczbie zasad.

Zgadzam się również ze wszystkimi innymi, że zestaw reguł powinien być oddzielny od ogólnego przepływu kodu, abyś mógł go łatwo dostosować bez zmiany programu. Możesz nawet wymyślić konkurencyjne zestawy reguł i zobaczyć, jak sobie radzą z prawdziwymi danymi dotyczącymi ruchu krów. Brzmi zabawnie.


0

Wspomniano systemy eksperckie, które są obszarem sztucznej inteligencji. Aby je nieco rozwinąć, przeczytaj o silnikach wnioskowania, które mogą ci w tym pomóc. Wyszukiwarka Google może być bardziej użyteczna - pisanie DSL jest łatwą częścią, możesz to zrobić trywialnie za pomocą parsera, takiego jak Gold Parser. Trudność polega na zbudowaniu drzewa decyzji i sprawnym ich przejściu.

Wiele systemów medycznych już korzysta z tych silników, na przykład brytyjska strona internetowa NHS Direct .

Jeśli jesteś .NET'erem, Infer.NET może być dla Ciebie przydatny.


0

Ponieważ patrzysz na ruch krowy, utknęły one w kierunku 360 stopni (krowy nie mogą latać.) Ty również masz wskaźnik, że podróżujesz. Można to zdefiniować jako wektor.

Jak sobie radzisz z takimi rzeczami jak położenie słońca, nachylenie wzgórza, głośny hałas?

Każdy ze stopni byłby zmienną oznaczającą chęć pójścia w tym kierunku. Powiedzmy, że gałązka uderza po prawej stronie krowy pod kątem 90 stopni (zakładając, że krowa jest skierowana w stronę 0 stopni). Pragnienie przejścia w prawo spadnie, a pragnienie przejścia 270 (w lewo) wzrośnie. Przejdź przez wszystkie bodźce, dodając lub odejmując ich wpływ na krowy, które chcą iść w określonym kierunku. Po zastosowaniu wszystkich bodźców krowa pójdzie w kierunku najwyższego pożądania.

Możesz także zastosować gradienty, aby bodźce nie musiały być binarne. Na przykład wzgórze nie jest proste w jednym kierunku. Może krowa znajduje się w dolinie lub na drodze na wzgórzu, gdzie jej mieszkanie było na wprost, na 45 * lekkim wzniesieniu przy 90 * lekkim zboczu. Na 180 * stromym wzgórzu.

Następnie możesz dostosować wagę wydarzenia i jego kierunek wpływu. Zamiast tego, jeśli tak, masz jeden test szukający maks. Również, jeśli chcesz dodać bodziec, możesz po prostu zastosować go przed testem i nie musisz zajmować się dodawaniem coraz większej złożoności.

Zamiast tego powiedzieć, że krowa pójdzie w dowolnym kierunku 360, po prostu podzielmy ją na 36 kierunków. Każdy ma 10 stopni

Zamiast tego powiedzieć, że krowa pójdzie w dowolnym kierunku 360, po prostu podzielmy ją na 36 kierunków. Każdy ma 10 stopni. W zależności od tego, jak konkretnie musisz być.


-2

Użyj OOP. Co powiesz na utworzenie grupy klas, które obsługują warunki podstawowe i uruchomienie losowych metod w celu symulacji tego, co robisz.

Poproś programistę o pomoc.

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

Dlaczego to ostatnia odpowiedź. Dochodzi do tego, że tysiące instrukcji if else jest po prostu sposobem na zaprojektowanie programu.
wfbarksdale,

1
Ponieważ zalecenie „ Użyj OOP. Poproś programistę o pomoc. ” Jest warte tego samego, co udzielenie porady „ Wykonuj więcej połączeń telefonicznych! ” Na pytanie „ Jak zwiększyć czterokrotnie sprzedaż? ”. Nie jest to całkowicie złe, ale też niewiele pomaga.
JensG

2
Głosowałem negatywnie, ponieważ to zła odpowiedź. Technicznie; twoja odpowiedź ma niewiele wspólnego z OOP. Wywołana klasa COW_METHODSwydaje się być niczym więcej niż zbiorem luźno powiązanych metod. Gdzie jest podział obaw? W związku z pytaniem, w jaki sposób pomaga pytającemu?
o
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.