Como se pode gerenciar milhares de regras IF… THEN… ELSE?

214

Estou pensando em criar um aplicativo que, em sua essência, consistiria em milhares de declarações if ... then ... else. O objetivo do aplicativo é prever como as vacas se movimentam em qualquer paisagem. Eles são afetados por coisas como sol, vento, fonte de alimento, eventos repentinos etc.

Como esse aplicativo pode ser gerenciado? Imagino que, depois de algumas centenas de declarações IF, seria tão imprevisível como o programa reagiria e depuraria o que leva a uma certa reação, significando que seria necessário percorrer toda a árvore de declarações IF sempre.

Eu li um pouco sobre os mecanismos de regras, mas não vejo como eles resolveriam essa complexidade.

David
fonte
22
Você precisa dar uma olhada na Programação DSL: en.wikipedia.org/wiki/Domain-specific_language Além disso, você também pode criar algum mecanismo de meta-regras controlado por dados. Por exemplo, você pode gerar modelos a partir de dados (por exemplo, KDD de mineração de dados)
Darknight
14
google para "sistema especialista" e "rete net"; boa sorte.
Steven A. Lowe
9
Mova as instruções if / then codificadas do código-fonte para dados externos que conduzem a simulação.
Kwebble
6
Coloquei alguns valores em um arquivo de texto e usei um loop para passar por um HashMap contendo nomes.
James P.
2
As perguntas de David - on Programmers são convertidas em CW quando mais de 15 respostas são postadas. Não podemos controlar quem publica a 16ª resposta.
ChrisF

Respostas:

73

A linguagem de programação lógica Prolog pode ser o que você está procurando. Sua declaração do problema não é específica o suficiente para eu avaliar se é uma boa opção, mas é bastante semelhante ao que você diz.

Um programa Prolog consiste em fatos e regras que são aplicadas. Aqui está um exemplo de regra simples que declara "Uma vaca se muda para um local se estiver com fome e houver mais comida no novo local do que no antigo":

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

Todas as letras maiúsculas são variáveis, coisas das quais você não sabe o valor. O Prolog tenta encontrar valores para essas variáveis ​​que satisfaçam todas as condições. Esse processo é realizado com um poderoso algoritmo chamado unificação, que é o coração do Prolog e ambientes de programação lógica semelhantes.

Além das regras, é fornecido um banco de dados de fatos. Um exemplo simples que funciona com as regras acima pode ser algo como:

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

Observe que vacas e pastagens brancas etc. não estão escritas em maiúsculas. Eles não são variáveis, são átomos.

Finalmente, você faz uma consulta e pergunta o que vai acontecer.

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

A primeira consulta pergunta para onde a vaca branca se moverá. Dadas as regras e os fatos acima, a resposta é Não. Isso pode ser interpretado como "Não sei" ou "Não se move", dependendo do que você deseja.

A segunda consulta pergunta para onde a vaca preta se move. Ele se move para o pasto para comer.

A pergunta final pergunta para onde todas as vacas se movem. Como resultado, você obtém todo o possível (vaca, destino) que faz sentido. Nesse caso, o touro preto se move para o pasto conforme o esperado. No entanto, o touro bravo tem duas opções que satisfazem as regras: pode passar para o pasto ou para o celeiro.

Nota: Faz anos desde a última vez que escrevi o Prolog, todos os exemplos podem não ser sintaticamente válidos, mas a ideia deve estar correta.

exDM69
fonte
10
-1: Eu não acho que o Prolog possa ser a resposta certa. Sim, pode ser fácil obter regras if-else no Prolog. Mas certamente você terá que fazer outra coisa. E não importa o que seja (IO; GUI, desenvolvimento web, ...), será uma dor com o Prolog.
Martin Thoma 13/10
4
Confira learnprolognow.com E embededing prólogo dentro de outro idioma é muito mais fácil do que costumava ser
Zachary K
@ZacharyK: O link está quebrado.
RenniePet
@ MartinThoma: você pode explicar o seu comentário? Os principais problemas com o Prolog IMHO são a falta de 1. uma maneira declarativa de controlar a pesquisa e 2. digitar. Mas se a sua aplicação não dependem fortemente estes dois, então eu não a priori ver um problema com o uso Prolog aqui
SN
139

Resolvendo o problema da web if, é possível criar um mecanismo de regras em que cada regra específica seja codificada independentemente. Um refinamento adicional para isso seria criar uma linguagem específica de domínio (DSL) para criar as regras, no entanto, apenas uma DSL desloca o problema de uma base de código (principal) para outra (DSL). Sem estrutura, o DSL não se sairá melhor do que a linguagem nativa (Java, C # etc.), portanto, voltaremos a ela depois de encontrarmos uma abordagem estrutural aprimorada.

A questão fundamental é que você está tendo um problema de modelagem. Sempre que você encontrar situações combinatórias como essa, é um sinal claro de que a abstração do seu modelo que descreve a situação é muito grossa. Você provavelmente está combinando elementos que devem pertencer a modelos diferentes em uma única entidade.

Se você continuar quebrando seu modelo, acabará por dissolver completamente esse efeito combinatório. No entanto, ao seguir esse caminho, é fácil se perder em seu design, criando uma confusão ainda maior, o perfeccionismo aqui não é necessariamente seu amigo.

Máquinas de estado finito e mecanismos de regras são apenas um exemplo de como esse problema pode ser quebrado e tornado mais gerenciável. A idéia principal aqui é que uma boa maneira de se livrar de um problema combinatório como esse é criar um design e repeti-lo ad-nauseam em níveis aninhados de abstração até que seu sistema funcione satisfatoriamente. Semelhante a como os fractais são usados ​​para criar padrões complexos. As regras permanecem as mesmas, não importa se você olha para o seu sistema com um microscópio ou com uma visão panorâmica.

Exemplo de aplicação disso ao seu domínio.

Você está tentando modelar como as vacas estão se movendo por um terreno. Embora sua pergunta não tenha detalhes, eu acho que sua grande quantidade de ifs inclui fragmentos de decisão como, if cow.isStanding then cow.canRun = truemas você fica atolado ao adicionar detalhes do terreno, por exemplo. Portanto, para cada ação que você deseja executar, verifique todos os aspectos em que você pode pensar e repita essas verificações para a próxima ação possível.

Primeiro, precisamos de nosso design repetitivo, que neste caso será um FSM para modelar os estados variáveis ​​da simulação. Portanto, a primeira coisa que eu faria é implementar um FSM de referência, definindo uma interface de estado , uma interface de transição e, talvez, um contexto de transiçãoque pode conter informações compartilhadas a serem disponibilizadas para os outros dois. Uma implementação básica do FSM mudará de uma transição para outra, independentemente do contexto; é aí que entra um mecanismo de regras. O mecanismo de regras encapsula de maneira limpa as condições que devem ser atendidas para que a transição ocorra. Um mecanismo de regras aqui pode ser tão simples quanto uma lista de regras, cada uma tendo uma função de avaliação retornando um valor booleano. Para verificar se uma transição deve ocorrer, itere a lista de regras e, se alguma delas for avaliada como falsa, a transição não ocorrerá. A transição em si conterá o código comportamental para modificar o estado atual do FSM (e outras tarefas possíveis).

Agora, se eu começar a implementar a simulação como um único FSM grande no nível GOD, terminarei com MUITOS estados possíveis, transições etc. A bagunça if-else parece que está consertada, mas na verdade é apenas espalhada: cada IF é agora uma regra que executa um teste com relação a informações específicas do contexto (que neste momento contêm praticamente tudo) e cada corpo IF está em algum lugar no código de transição.

Digite a decomposição dos fractais: o primeiro passo seria criar um FSM para cada vaca, onde os estados são os estados internos da própria vaca (em pé, correndo, andando, pastando etc.) e as transições entre elas seriam afetadas pelo ambiente. É possível que o gráfico não esteja completo, por exemplo, o pastoreio só é acessível a partir do estado permanente, qualquer outra transição é desaprovada, porque simplesmente está ausente no modelo. Aqui você efetivamente separa os dados em dois modelos diferentes, a vaca e o terreno. Cada um com seu próprio conjunto de propriedades. Essa análise permitirá que você simplifique o design geral do seu motor. Agora, em vez de ter um único mecanismo de regras que decide tudo, você tem vários mecanismos de regras mais simples (um para cada transição) que decidem detalhes muito específicos.

Como estou reutilizando o mesmo código para o FSM, isso é basicamente uma configuração do FSM. Lembra quando mencionamos as DSLs anteriormente? É aqui que o DSL pode fazer muito bem se você tiver muitas regras e transições para escrever.

Indo mais fundo

Agora, DEUS não precisa mais lidar com toda a complexidade no gerenciamento dos estados internos da vaca, mas podemos avançar ainda mais. Ainda há muita complexidade envolvida no gerenciamento do terreno, por exemplo. É aqui que você decide onde a repartição é suficiente. Se, por exemplo, no seu DEUS você acaba gerenciando a dinâmica do terreno (grama alta, lama, lama seca, grama curta, etc.), podemos repetir o mesmo padrão. Não há nada que impeça a incorporação dessa lógica no próprio terreno, extraindo todos os estados do terreno (grama longa, grama curta, lamacenta, seca etc.) em um novo FSM de terreno com transições entre os estados e talvez regras simples. Por exemplo, para chegar ao estado lamacento, o mecanismo de regras deve verificar o contexto para encontrar líquidos, caso contrário, não é possível. Agora DEUS ficou mais simples ainda.

Você pode concluir o sistema do FSM, tornando-os autônomos e dando a cada um deles um encadeamento. Este último passo não é necessário, mas permite alterar dinamicamente a interação do sistema, ajustando a forma como você delega sua tomada de decisão (iniciando um FSM especializado ou apenas retornando um estado predeterminado).

Lembre-se de como mencionamos que as transições também podem fazer "outras tarefas possíveis"? Vamos explorar isso adicionando a possibilidade de diferentes modelos (FSM) se comunicarem. Você pode definir um conjunto de eventos e permitir que cada FSM registre o ouvinte desses eventos. Assim, se, por exemplo, uma vaca entra em um terreno hexadecimal, o hex pode registrar ouvintes para alterações de transição. Aqui fica um pouco complicado, porque cada FSM é implementado em um nível muito alto, sem qualquer conhecimento do domínio específico que abriga. No entanto, você pode conseguir isso fazendo com que a vaca publique uma lista de eventos e a célula pode se registrar se vir eventos aos quais pode reagir. Uma boa hierarquia da família de eventos aqui é um bom investimento.

Você pode avançar ainda mais modelando os níveis de nutrientes e o ciclo de crescimento da grama, com ... você adivinhou ... um FSM de grama incorporado ao modelo do terreno.

Se você empurrar a idéia longe o suficiente, DEUS terá muito pouco a fazer, pois todos os aspectos são praticamente autogerenciados, liberando tempo para gastar em coisas mais piedosas.

Recapitular

Como mencionado acima, o FSM aqui não é a solução, apenas um meio para ilustrar que a solução para esse problema não é encontrada no código, por exemplo, mas como você modela seu problema. É provável que outras soluções sejam possíveis e muito melhores que minha proposta de FSM. No entanto, a abordagem "fractais" continua sendo uma boa maneira de lidar com essa dificuldade. Se feito corretamente, você pode alocar dinamicamente níveis mais profundos onde importa, enquanto fornece modelos mais simples onde menos importa. Você pode enfileirar alterações e aplicá-las quando os recursos ficarem mais disponíveis. Em uma sequência de ações, pode não ser tão importante calcular a transferência de nutrientes da vaca para a grama. No entanto, você pode registrar essas transições e aplicar as alterações posteriormente ou apenas aproximar-se com um palpite, substituindo os mecanismos de regras ou talvez substituindo a implementação do FSM por uma versão ingênua mais simples para os elementos que não estão no campo direto de interesse (aquela vaca no outro extremo do campo) para permitir que interações mais detalhadas obtenham o foco e uma parcela maior de recursos. Tudo isso sem nunca revisitar o sistema como um todo; Como cada peça é bem isolada, fica mais fácil criar uma substituição imediata limitando ou estendendo a profundidade do seu modelo. Ao usar um design padrão, você pode aproveitar isso e maximizar os investimentos feitos em ferramentas ad-hoc, como uma DSL, para definir regras ou um vocabulário padrão para eventos, começando novamente em um nível muito alto e adicionando aprimoramentos, conforme necessário. Como cada peça é bem isolada, fica mais fácil criar uma substituição imediata limitando ou estendendo a profundidade do seu modelo. Ao usar um design padrão, você pode aproveitar isso e maximizar os investimentos feitos em ferramentas ad-hoc, como uma DSL, para definir regras ou um vocabulário padrão para eventos, começando novamente em um nível muito alto e adicionando aprimoramentos, conforme necessário. Como cada peça é bem isolada, fica mais fácil criar uma substituição imediata limitando ou estendendo a profundidade do seu modelo. Ao usar um design padrão, você pode aproveitar isso e maximizar os investimentos feitos em ferramentas ad-hoc, como uma DSL, para definir regras ou um vocabulário padrão para eventos, começando novamente em um nível muito alto e adicionando aprimoramentos, conforme necessário.

Eu forneceria um exemplo de código, mas isso é tudo o que posso fazer agora.

Newtopian
fonte
11
Aceitei esta resposta, porque é uma ordem de magnitude melhor para explicar uma solução do que as outras. No entanto, posso alterar minha resposta aceita se uma melhor aparecer. Sua solução também parece radical o suficiente para fazer a diferença. No entanto, ainda estou tendo problemas para entender como definir as regras sobre como os diferentes modelos devem interagir. Você poderia fazer um exemplo disso?
David
-1 Não vejo por que isso não pode ser simplesmente resolvido através de uma árvore de decisão? (juntamente com uma DSL que pega o modelo e o transforma em código executável)?
Darknight
14
DEUS vs o FSM?
precisa saber é o seguinte
11
As árvores de decisão e os mecanismos de regras são usados ​​precisamente nos casos em que não há valor intrínseco para modelar os aspectos em questão, pois eles são apenas um meio para o fim de um cálculo. Você vê isso no software de assistência médica o tempo todo. Dito isto, se você estiver tentando modelar o comportamento real, tente e faça isso. Existem muitos casos em que a única lógica encontrada em um problema é o resultado de milhares de se isso é ad infinitum. E é válido, é por isso que temos ferramentas para lidar com isso.
Delete_user 17/09/12
11
Isso provou muito sucesso no mundo da programação de jogos; é muito mais rápido e fácil alterar uma regra ou propriedade e deixar o comportamento emergir, depois examinar um valor para decidir como agir de acordo com ele.
Ben Leggiero
89

Parece que todas essas declarações condicionais das quais você está falando devem realmente ser dados que configuram seu programa e não parte do próprio programa. Se você puder tratá-los dessa maneira, poderá modificar o funcionamento do seu programa apenas alterando sua configuração, em vez de precisar modificar seu código e recompilar toda vez que quiser melhorar seu modelo.

Existem várias maneiras diferentes de modelar o mundo real, dependendo da natureza do seu problema. Suas várias condições podem se tornar regras ou restrições aplicadas à simulação. Em vez de ter um código parecido com:

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

você pode ter um código parecido com:

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

Ou, se você puder desenvolver um programa linear que modele o comportamento das vacas, com várias entradas, cada restrição poderá se tornar uma linha em um sistema de equações. Você pode transformar isso em um modelo de Markov que pode ser iterado.

É difícil dizer qual é a abordagem correta para sua situação, mas acho que você terá mais facilidade se considerar que suas restrições são entradas para o seu programa e não código.

Caleb
fonte
4
Por favor, descreva como "cow.apply (rule);" funciona com arquivos de configuração?
Kromster
8
@ Krom, é difícil dizer em termos concretos sem saber de que tipo de sistema estamos falando. Meu argumento acima é tratar as milhares de condições como entradas para o programa, para que você não precise escrever código para cada uma e possa alterar as condições sem alterar o programa. Mas sim, se as condições puderem ser tratadas como dados, você as armazenará separadamente do programa em algum tipo de documento ou arquivo de configuração.
Caleb
2
@Krom - Simples. Você deve ler a regra e aplicá-la à vaca especificada.
Ramhound 26/08/11
5
Mover código para arquivos de configuração nem sempre é uma boa abordagem. É difícil depurar mágica.
21712 Ricky Clarkson
44

Ninguém mencionou isso, então eu pensei em dizer isso explicitamente:

Milhares de regras "If .. Then .. Else" são um sinal de um aplicativo mal projetado.

Embora a representação de dados específicos do domínio possa parecer com essas regras, você tem certeza absoluta de que sua implementação deve se parecer com a representação específica do domínio?

blueberryfields
fonte
18
Não é necessariamente verdade. Existem problemas que só podem ser resolvidos através de enormes árvores de decisão. Mas é claro que uma solução para aqueles compostos por uma árvore literal de se-então-outro é mal projetada. Existem maneiras muito mais flexíveis e sustentáveis ​​de fazer isso.
SF.
43
Eu pensei que esse era o objetivo da pergunta. O OP tem um problema específico ao seu domínio que, em uma implementação ingênua, exigiria milhares de se ... então ... mais. Ele tinha a intuição de que isso seria problemático e perguntou a essa comunidade sobre melhores maneiras de fazer isso. O simples fato de a pergunta ter sido feita é uma boa indicação de que isso já foi entendido; sua resposta, embora correta, não ajuda em nada a questão.
Newtopian 29/08/11
@ Newtopian Um usuário ou programador avançado entenderia isso e consideraria óbvio. Um usuário ou programador ingênuo pode não perceber isso. Eu afirmei conscientemente o que a maioria das pessoas considera óbvio - confirmei que o OP está correto em sua suposição de que isso seria problemático e, definitivamente, não deve ir com a implementação imediata ou ingênua.
Blueberryfields
Concordo, você pode substituir, se houver, por polimorfismo, bem como DI. se você tem zilhões de senão, seu design é muito ruim.
DarthVader
17

Por favor, use linguagens de software / computador adequadas para a tarefa. O Matlab é usado com frequência para modelar sistemas complexos, nos quais você pode ter literalmente milhares de condições. Não usando cláusulas if / then / else, mas por análise numérica. R é uma linguagem de computador de código aberto repleta de ferramentas e pacotes para fazer o mesmo. Mas isso significa que você também precisa reexaminar seu modelo em termos mais matemáticos, para poder incluir as principais influências e as interações entre influências nos modelos.

Se você ainda não o fez, siga um curso sobre modelagem e simulação. A última coisa que você deve fazer é considerar escrever um modelo como esse em termos de se - então - outra coisa. Temos cadeias monte carlo markov, máquinas de vetores de suporte, redes neurais, análise de variáveis ​​latentes, ... Por favor, não se jogue 100 anos atrás, ignorando a riqueza das ferramentas de modelagem disponíveis.

Joris Meys
fonte
Estou surpreso como essa pergunta recebeu tão pouca atenção. A análise e modelagem numérica é, em essência, uma máquina if-else. No entanto, sofre de falsos positivos que podem não ser tolerados se a aplicação for estritamente necessária às regras. (Think banking)
Arun Jose
13

Os mecanismos de regras podem ajudar porque, se houver muitas regras if / then, pode ser útil colocá-las em um único local fora do programa, onde os usuários podem editá-las sem a necessidade de conhecer uma linguagem de programação. Além disso, ferramentas de visualização podem estar disponíveis.

Você também pode procurar soluções de programação lógica (como o Prolog). Você pode modificar rapidamente a lista de instruções if / then e fazer com que faça coisas como verificar se alguma combinação de entradas levaria a determinados resultados etc. Também pode ser mais limpo na lógica de predicados de primeira ordem do que no código de procedimento (ou no código orientado a objetos).

psr
fonte
11

De repente me ocorreu:

Você precisa usar uma Árvore de Aprendizado de Decisão (Algoritmo ID3).

É muito provável que alguém o tenha implementado no seu idioma. Caso contrário, você pode portar uma biblioteca existente

Noite escura
fonte
Vá com a idéia DSL dada acima. Tente descobrir como abstrair o problema de alguma forma de uma álgebra simbólica e, em seguida, implemente isso.
Zachary K
11

Esta é mais uma resposta do wiki da comunidade, agregando as várias ferramentas de modelagem sugeridas por outras respostas. Acabei de adicionar links adicionais aos recursos.

Acho que não há necessidade de reafirmar que você deve usar uma abordagem diferente para milhares de instruções if / else codificadas.

ocodo
fonte
9

Todo aplicativo grande contém milhares de if-then-elseinstruções, sem contar outros controles de fluxo, e esses aplicativos ainda são depurados e mantidos, apesar de sua complexidade.

Além disso, o número de instruções não torna o fluxo imprevisível . Programação assíncrona faz. Se você usar algoritmos determinísticos de forma síncrona, sempre terá um comportamento 100% previsível.

Você provavelmente deve explicar melhor o que está tentando fazer no Stack Overflow ou no Code Review, para que as pessoas possam sugerir as técnicas precisas de refatoração a serem usadas. Você também pode fazer perguntas mais precisas, como "Como evito aninhar muitas ifinstruções <dado um pedaço de código>".

Arseni Mourzenko
fonte
11
A maioria dos aplicativos possui 2-3 níveis de aninhamento e condições de 1 linha. Que tal um problema que requer uma árvore de decisão aninhada a 50 níveis, e muitas condições sendo compostos lógicos de 30 ou mais variáveis ​​cada?
SF.
Embora "Todo aplicativo grande ..." seja certamente verdadeiro, é bastante claro que o OP está falando sobre longas sequências de expressões condicionais que essencialmente formam as regras em um modelo. Grupos enormes de ifdeclarações aninhadas rapidamente se tornam difíceis de manejar, na melhor das hipóteses, por isso é necessária uma abordagem melhor.
Caleb
@Caleb: você está certo, é claro agora , com o exemplo preciso no início da questão. Não foi antes de a pergunta ser editada quando escrevi minha resposta. Isso explica a incoerência real de minhas e de outras duas respostas postadas ao mesmo tempo.
Arseni Mourzenko
2

Torne seu aplicativo gerenciável, projetando-o bem. Projete seu aplicativo dividindo as várias lógicas de negócios em classes / módulos separados. Escreva testes de unidade que testam cada uma dessas classes / módulos individualmente. Isso é crucial e ajudará a garantir que a lógica de negócios seja implementada conforme o esperado.

Bernard
fonte
2

Provavelmente, não haverá uma maneira única de solucionar o problema, mas você pode gerenciar a complexidade, peça por peça, se tentar separar diferentes áreas nas quais se encontra escrevendo grandes blocos de instruções if e aplicando soluções para cada um desses problemas menores.

Observe técnicas como as regras mencionadas na refatoração para descobrir maneiras de dividir grandes condicionais em partes gerenciáveis ​​- várias classes com uma interface comum podem substituir uma instrução de caso, por exemplo.

Sair cedo também é uma grande ajuda. Se você tiver condições de erro, afaste-as no início da função lançando uma exceção ou retornando em vez de deixá-las aninhadas.

Se você dividir suas condições em funções predicadas, pode ser mais fácil controlá-las. Além disso, se você pode obtê-los em um formulário padrão, pode ser possível obtê-los em uma estrutura de dados criada dinamicamente, em vez de codificada.

Dan Monego
fonte
2

Eu sugiro que você use um mecanismo de regras. No caso de Java, o jBPM ou o Oracle BPM podem ser úteis. Os mecanismos de regras basicamente permitem que você configure o aplicativo através de XML.

Sid
fonte
+1 Tenho usado Drools recentemente, juntamente com o Mvel, como o idioma para expressar as regras, e é exatamente isso que você está procurando. Não obstante o fato de ser muito rápido.
precisa saber é o seguinte
Baba é uma boa escolha. Pessoalmente, estou usando o Oracle BPM agora. Há também Feugo. Muitas ferramentas de código aberto e propriedade disponíveis.
Sid
2

O problema não está bem resolvido por "regras", seja descrito pelo código de procedimento "se-então" ou pelas inúmeras soluções de regras criadas para aplicativos de negócios. O aprendizado de máquina fornece vários mecanismos para modelar esses cenários.

Fundamentalmente, é preciso formular algum esquema para a representação discreta dos fatores (por exemplo, sol, vento, fonte de alimento, eventos repentinos etc.) que influenciam o "sistema" (isto é, vacas no pasto). Não obstante a crença equivocada de que se pode criar uma representação funcional com valor real, em vez de discreta, nenhum computador no mundo real (incluindo o sistema nervoso humano) é baseado em valores reais ou calculado com base em valores reais.

Depois de ter sua representação numérica para os fatores relevantes, você pode construir qualquer um dos vários modelos matemáticos. Eu sugeriria um gráfico bipartido em que um conjunto de nós representa vacas e outro alguma área unitária de pastagem. Em qualquer caso, uma vaca ocupa uma área unitária de pasto. Para cada vaca existe um valor de utilidade associado à atual e a todas as outras unidades de pastagem. Se o modelo pressupõe que a vaca procura otimizar (o que isso significa para a vaca) o valor da utilidade de sua unidade de pastagem, as vacas se moverão de unidade para unidade, na tentativa de otimizar.

Um automate celular funciona bem para executar o modelo. A matemática subjacente no mundo da matemática de valor real que motiva o movimento das vacas é um modelo de gradiente de campo. As vacas passam de posições de menor valor de utilidade percebido para posições de maior valor de utilidade percebido.

Se alguém injetar mudanças ambientais no sistema, ele não se moverá para uma solução em estado estacionário de posicionamento da vaca. Também se tornará um modelo ao qual aspectos da teoria dos jogos podem ser aplicados; não que isso traga necessariamente muito a este caso.

A vantagem aqui é o abate de vacas ou a aquisição de novas vacas, que pode ser facilmente gerenciada subtraindo e adicionando células "vacas" ao gráfico bipartido, enquanto o modelo está em execução.

Charles
fonte
1

Não acho que você deva definir tantas declarações if-else. Do meu ponto de vista, seu problema tem vários componentes:

  • Deve ser assíncrono ou multithread, porque você tem várias vacas com personalidades diferentes, configurações diferentes. Cada vaca se pergunta em qual direção seguir antes do próximo passo. Na minha opinião, um código de sincronização é uma ferramenta ruim para esse problema.

  • A configuração da árvore de decisão muda constantemente. Depende da posição da vaca, do tempo, do tempo, do terreno, etc. Em vez de construir uma árvore se-else complexa, acho que deveríamos reduzir o problema a uma rosa dos ventos ou a uma direção - função de peso : figura 1 figura 1 - direção - funções de peso para algumas regras

    A vaca deve sempre ir para a direção que tem o maior peso total. Portanto, em vez de construir uma grande árvore de decisão, você pode adicionar um conjunto de regras (com diferentes funções de direção - peso) a cada vaca e simplesmente processar o resultado sempre que pedir a direção. Você pode reconfigurar essas regras a cada mudança de posição, ou passando o tempo, ou pode adicionar esses detalhes como parâmetros que todas as regras devem receber. É uma decisão de implementação. A maneira mais simples de obter uma direção, adicionar um loop simples de 0 ° a 360 ° com passo de 1 °. Depois disso, você pode contar a soma do peso de cada direção 360 e executar uma função max () para obter a direção correta.

  • Você não precisa necessariamente de uma rede neural para fazer isso, apenas uma classe para cada regra, uma classe para as vacas, talvez para o terreno, etc ... e uma classe para o cenário (por exemplo, 3 vacas com regras diferentes e 1 terreno específico). Figura 2 figura 2 - nós e conexões de decisão assíncrona do aplicativo cow

    • vermelho para a direção das mensagens - mapa de pesos através das regras
    • azul para atualizações de orientação e posição após a tomada de decisão
    • verde para atualizações de entrada após atualização de orientação e posição
    • preto para obter entradas

    nota: você provavelmente precisará de uma estrutura de mensagens para implementar algo como isto

    Portanto, se criar vacas aprendizes não faz parte do seu problema, você não precisa de uma rede neural ou de algoritmos genéticos. Não sou especialista em IA, mas acho que se você quiser adaptar suas vacas às reais, poderá fazê-lo simplesmente com um algoritmo genético e o conjunto de regras adequado. Se bem entendi, você precisa de uma população de vacas com configurações aleatórias de regras. Depois disso, você pode comparar o comportamento de vacas reais com o comportamento da população modelo e manter 10%, que seguem o caminho mais próximo dos reais. Depois disso, você pode adicionar novas restrições de configuração de regras à sua fábrica de vacas com base nos 10% que você manteve e adicionar novas vacas aleatórias à população, e assim por diante, até obter uma vaca modelo que se comporte exatamente como as reais ...

inf3rno
fonte
0

Eu acrescentaria que pode ser que, se você realmente tenha milhares de regras IF ... THEN, poderá estar superespecificando. Pelo que vale a pena, as palestras sobre modelagem de redes neurais que participei geralmente começam com a afirmação de que, com "um conjunto simples de regras", elas podem gerar um comportamento bastante complexo e razoavelmente compatível com a realidade (de, nesses casos, neurônios reais em ação). Então, você tem certezavocê precisa de milhares de condições? Quero dizer, além de 4-5 aspectos do clima, localização de fontes de alimentos, eventos repentinos, pastoreio e terreno, você realmente terá muito mais variáveis? Claro, se você tentasse fazer todas as permutações possíveis de combinar essas condições, poderia facilmente ter muitos milhares de regras, mas essa não é a abordagem correta. Talvez uma abordagem de estilo lógico difuso, na qual os vários fatores introduzam um viés na localização de cada vaca, combinada com uma decisão geral, permita que você faça isso com muito menos regras.

Também concordo com todos os demais que o conjunto de regras deve ser separado do fluxo geral de código, para que você possa ajustá-lo facilmente sem alterar o programa. Você pode até criar conjuntos de regras concorrentes e ver como eles se saem em relação aos dados reais do movimento das vacas. Parece divertido.

Chelonian
fonte
0

Sistemas especialistas foram mencionados, que são uma área da IA. Para expandir um pouco sobre isso, ler os Inference Engines pode ajudá-lo com isso. Uma pesquisa no Google pode ser mais útil - escrever a DSL é a parte mais fácil, você pode fazer isso trivialmente com um analisador como o Gold Parser. A parte difícil vem da construção de sua árvore de decisões e da execução eficiente delas.

Muitos sistemas médicos já usam esses mecanismos, por exemplo, o site NHS Direct do Reino Unido .

Se você é um .NET'er, o Infer.NET pode ser útil para você.

Chris S
fonte
0

Desde que você olha o movimento da vaca, ela fica presa na direção de 360 ​​graus (as vacas não podem voar.) Você também tem uma taxa que está viajando. Isso pode ser definido como um vetor.

Agora, como você lida com coisas como a posição do sol, a inclinação da colina, o barulho alto?

Cada um dos graus seria uma variável que significa o desejo de ir nessa direção. Digamos que um galho se encaixe à direita da vaca a 90 graus (assumindo que a vaca esteja voltada para 0 graus). O desejo de ir para a direita diminuirá e o desejo de ir 270 (esquerda) aumentará. Passe por todos os estímulos adicionando ou subtraindo sua influência sobre as vacas que desejam seguir uma direção. Uma vez aplicados todos os estímulos, a vaca irá na direção do desejo mais elevado.

Você também pode aplicar gradientes para que os estímulos não precisem ser binários. Por exemplo, uma colina não é reta em uma direção. Talvez a vaca esteja em um vale ou em uma estrada em uma colina, se a sua planície estivesse sempre em frente, a 45 * subindo a colina a 90 * subindo a colina. A 180 * subida íngreme.

Você pode ajustar o peso de um evento e sua direção de influência. Em vez de uma lista de se houver, você tem um teste procurando o valor máximo. Além disso, quando você quiser adicionar um estímulo, basta aplicá-lo antes do teste e não precisará adicionar mais e mais complexidade.

Em vez de dizer que a vaca seguirá em qualquer direção 360, basta dividi-la em 36 direções. Cada um sendo 10 graus

Em vez de dizer que a vaca seguirá em qualquer direção 360, basta dividi-la em 36 direções. Cada um sendo 10 graus. Dependendo de quão específico você precisa ser.

Zero
fonte
-2

Use OOP. Que tal criar um monte de classes que lidam com as condições básicas e executam métodos aleatórios para simular o que você está fazendo.

Peça a um programador para ajudá-lo.

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
fonte
Por que essa é a última resposta? Chega ao ponto, que é que agora milhares de instruções if else são apenas uma maneira de criar um programa.
Wfbarksdale
11
Porque recomendar " Use OOP. Peça ajuda a um programador. " É o mesmo que dar o conselho " Faça mais ligações! " Quando perguntado " Como posso quadruplicar minhas vendas? ". Não é estritamente errado, mas também não ajuda muito.
JensG
2
Fiz voto negativo, porque esta é uma resposta ruim. Tecnicamente; sua resposta tem pouco a ver com OOP. Uma classe chamada COW_METHODSparece ser nada mais que uma coleção de métodos vagamente relacionados. Onde está a separação de preocupações? Relacionado à pergunta, como isso ajuda o solicitante?
oɔɯǝɹ