Algoritmo de calendário / planejamento


24

Estou enfrentando um problema que não sei ao certo como abordar. Eu tenho que gerar um calendário para os funcionários, cada um deles com restrições de trabalho específicas (algumas pessoais, outras comuns)

Com o que estou trabalhando:

  • Eu tenho doutores
  • Cada médico tem que trabalhar 5 dias / semana.
  • Cada médico tem que trabalhar 1 noite / semana
  • Cada médico deve trabalhar uma quantidade igual de noites em comparação com outros médicos (ou o mais próximo possível)
  • Cada médico deve trabalhar uma quantidade igual de noites de quinta e domingo em comparação com outros médicos (ou o mais próximo possível)
  • Alguns médicos não podem trabalhar em determinados dias / noites (informações do usuário)
  • Alguns médicos gostariam de trabalhar em determinados dias / noites (informações do usuário)
  • Alguns médicos gostariam de não trabalhar determinados dias / noites (informações do usuário)

O usuário em questão é a pessoa que lida com o calendário. Estou tentando criar uma solução que gere automaticamente um calendário que obedeça a todas as restrições. A solução é apenas uma grande entrada de configurações "adicionar médicos" e "adicionar restrições" para cada médico e, em seguida, um botão "gerar calendário". É realmente básico para o usuário.

Meu problema :

Não tenho certeza de como gerar o planejamento real, tenho lido sobre Redes Neurais, Algoritmos Genéticos e assim por diante, e todas elas parecem ser a solução certa, mas também não são realmente.

Quando olho para os GAs, eles são feitos para encontrar uma solução com uma determinada população (meu problema), mas a população inicial já deve obedecer a um determinado conjunto de restrições, que seria otimizado. Nesse caso, minha população inicial já é a solução. Não preciso que seja "otimizado". Não importa que uma única pessoa trabalhe três noites de segunda-feira seguidas, desde que esteja realmente correta e que outras pessoas trabalhem a mesma quantidade, isso significa que outras pessoas também trabalharão três noites de segunda-feira em algum momento e tudo bem. O que me faz pensar que os GAs são "avançados" demais para mim, pois meu problema já foi resolvido com o ponto de partida de um GA.

Mas, novamente, os GAs realmente parecem feitos para isso, então eu posso não estar entendendo corretamente?

De qualquer forma, como eu nunca usei GAs (ou redes neurais, ou qualquer coisa do tipo), gostaria de ter certeza de que estou adotando a abordagem correta antes de iniciar uma curva de aprendizado como essa.

Minha pergunta :

O que você acha que é uma boa abordagem / algoritmo / técnica para um problema como o meu? Gás? Redes neurais? Algo completamente diferente?

Sou todo ouvidos e abertos a mais detalhes, se necessário, mas acho que me deixei bem claro :)


22
Provavelmente vale a pena olhar para a literatura em torno do problema enfermeira rostering en.wikipedia.org/wiki/Nurse_scheduling_problem
Renaud M.

Um termo tão conveniente! Hehe, obrigado pelo seu link;)
Gil Sand

8
Não sou especialista nesta área, no entanto, se o que você procura é uma abordagem que poupe algum tempo no desenvolvimento, pode valer a pena tentar modelar o problema como um Problema de Programação Inteira Mista ( en.wikipedia. org / wiki / Linear_programming # Integer_unknowns ) e insira-o em um solucionador MIP ou como um problema de programação de restrição e insira-o em um solucionador de CP, como OR-tools ( developers.google.com/optimization ). Dessa forma, tudo que você precisa fazer é expressar seu problema.
Renaud M.

3
A programação linear é garantida para obter asolução ideal !
recursion.ninja

2
@RenaudM. É uma pena que poucos programadores profissionais entendam esse campo incrivelmente útil da matemática. Sempre que alguém sugere recozimento simulado ou algoritmos genéticos para fora do lado do campo de AI, a minha resposta intestino é: Provavelmente pode ser mais bem modelado como uma otimização Programa Linear
recursion.ninja

Respostas:


14

Algoritmos genéticos e redes neurais não são adequados aqui. São meta-heurísticas para encontrar uma solução aproximada e suficientemente boa para um problema. Notavelmente, ambos exigem que você encontre uma função de custo para classificar as soluções candidatas. Depois de ter essa função de custo, pode ser mais fácil criar manualmente um algoritmo que otimize esse custo.

Este é um pensamento importante: dados dois cronogramas, precisamos de uma maneira de decidir se o cronograma A ou o cronograma B é "melhor". Você listou vários critérios, mas não está claro como eles se relacionam. Deixar de cumprir um critério falha em toda a solução? Ou a falha parcial de uma restrição apenas a torna uma solução pior do que outras?

No nível mais básico, você pode apenas dividir a semana em intervalos de tempo discretos e aplicar força bruta em todas as combinações de slot-médico. No entanto, você pode usar restrições rígidas para reduzir esse espaço de pesquisa para um tamanho mais gerenciável. As restrições de horário de trabalho e turnos noturnos parecem ser adequadas para essa limitação de espaço de pesquisa. Você fica com centenas de soluções candidatas.

Para selecionar a melhor solução candidata, você precisará classificá-las. Isso é bastante fácil se uma restrição moderada tiver precedência clara sobre todas as outras restrições moderadas, por exemplo, se um médico não puder trabalhar em um determinado turno, isso terá mais importância do que um médico que não deseja trabalhar nesse turno. Mas não posso decidir essas regras para você - essa é uma decisão gerencial. É mais difícil se duas restrições flexíveis não tiverem precedência clara; nesse caso, você precisará criar algum tipo de função de custo que unifique a importância de duas restrições em uma única métrica.


Eu provavelmente construiria um algoritmo ganancioso que preenche um horário em branco de acordo com alguns critérios priorizados. Essa pode não ser a solução mais ideal, mas é muito mais fácil do que filosofar sobre o que “ideal” realmente significa.

Como primeiro passo, você pode preencher os turnos da noite nos fins de semana e tentar selecionar os médicos que não fazem o turno da noite de fim de semana há mais tempo, levando em conta também os desejos do usuário "Eu não posso trabalhar lá" . Supondo que esses desejos sejam semanais e não contínuos, isso significa que um médico que não pode trabalhar nas noites de fim de semana por uma semana seria escolhido na próxima semana.

Um procedimento semelhante pode ser usado para as outras noites: depois de tentar respeitar os desejos do usuário, você preenche os médicos de acordo com quem não trabalha no turno da noite há mais tempo. O procedimento se repete da mesma forma para o terceiro tipo de intervalo de tempo, o dia muda. Se dois desejos do usuário não puderem ser reconciliados, você poderá acompanhar com que frequência o desejo do usuário foi atendido e, em seguida, priorizar o médico com menos desejos concedidos.

Infelizmente, eu posso ver algumas maneiras de usar esse sistema: por exemplo, se um médico fosse escolhido para trabalhar no turno da noite de fim de semana, mas solicitasse um "não pode trabalhar lá", a escolha seria adiada uma semana - reduzindo sua frequência dos turnos da noite de fim de semana às custas de seus colegas. Se um procedimento de resolução de desejo for implementado, analisando o número de solicitações recusadas, um usuário poderá fazer algumas solicitações impossíveis para impulsionar uma solicitação pela qual deseja passar. No entanto, assumindo boa fé (e a flexibilidade para os médicos trocarem de turno entre si), esse algoritmo deve resultar em uma solução suficientemente boa.


Obrigado pela sua resposta, vou me aprofundar um pouco mais nisso com meu colega :) Para fornecer mais informações: sim, podemos classificar a maioria das soluções / critérios e decidir se alguns têm precedência sobre outros. Além disso, eles estão realmente trabalhando de boa fé agora, e está funcionando bem. Eles usam a mão e não usam muito o "eu não posso trabalhar naquele dia". É muito bom como eles conseguem isso agora, porque realmente fazem isso manualmente . Então uma solução "viável" já significa o mundo para eles, e salvá-los um monte de tempo de brainstorming de quem pode trabalhar quando
Gil Areia

5
@Zil, as pessoas que estão criando os horários já estão provavelmente usando um algoritmo informal. Você poderia simplesmente falar com eles e tentar entender o processo de decisão deles, depois formalizar e implementar isso. Isso seria muito mais fácil do que configurar e treinar uma rede neural.
amon

Esse é o nosso primeiro passo: já temos uma reunião com eles! Obrigado por toda sua ajuda :)
Gil Areia

3
Para este caso de uso, os algoritmos genéticos são consistentemente inferiores ao Tabu Search e Simulated Annealing, conforme comprovado pelas competições de pesquisa International Nurse Rostering Competitions. (Mas, claro, eles ainda são melhores do que apenas um algo ganancioso.)
Geoffrey De Smet

12

Você pode usar o recozimento simulado .

Fiz algo assim antes de conseguir meu primeiro emprego - veja https://vimeo.com/20610875 (demonstração a partir das 2:50, algoritmo explicado a partir das 6:15).

O recozimento simulado é um tipo de algoritmo genético, e talvez não seja adequado na teoria (como @amon mantém em sua resposta ), mas funcionou muito bem na prática e foi sobre o mesmo caso de uso que o seu.

O código-fonte está disponível (C #), mas, embora funcione, é terrível, temo, há alguns anos atrás e sendo um autodidata, eu não sabia nada sobre manutenção. Mas produziu resultados muito bons.

De qualquer maneira, como funciona em poucas palavras:

  • Gere 1 horário possível (pode não ser muito bom, mas fisicamente possível) como ponto de partida. O algoritmo genético não é necessário neste momento - você pode apenas forçar o caminho até a primeira solução que encontrar. Eu usei retroceder . A complexidade computacional pode ser superada resolvendo a rota para cada dia separadamente. Se não houver solução (como pode ser o caso), é nesse ponto que você a detecta.

  • Faça um pool de soluções - digamos, 100 cópias dessa solução básica para começar.

  • Mude todas as soluções aleatoriamente: peça aos médicos que troquem turnos entre si, tirem um médico aleatório do turno e coloque uma pessoa disponível aleatoriamente etc.

  • Avalie cada solução com uma função de condicionamento físico que determina como é boa. Um cara trabalha mais noites que outro? Subtrair pontos de penalidade. Alguém queria fazer segunda-feira, mas não? Subtrair pontos de penalidade novamente.

  • Tome - digamos - 20 melhores soluções e copie cada uma delas 5 vezes, substituindo as 80 restantes, levando-as para a próxima geração. Sobrevivência do mais forte.

  • Enxágüe e repita.

Os números são obviamente arbitrários; talvez seja necessário mexer nos parâmetros para descobrir as configurações ideais para o seu cenário.

Quanto à mutação de uma solução, o recozimento simulado introduz algo chamado temperatura. Basicamente, isso significa que, no começo, você deve alterar suas soluções com bastante força (por exemplo, sempre faça 10 tentativas de troca de turnos de uma só vez) e gradualmente se torne menos agressivo com as iterações subsequentes, para que elas se tornem mais ajustadas (por exemplo, para baixo) apenas 2 tentativas de ajuste por geração).


4
Usei o OptaPlanner (nee Drools Planner) com o Simulated Annealing para um horário da faculdade. Declarar os modelos - um turno tem um tempo e um médico. Escreva regras declarativas para a função de condicionamento físico - restrições rígidas (um médico não pode fazer turnos sobrepostos) e multas (Ann odeia segundas-feiras). Escreva trocas declarativas (esse é o ponto!) De turnos. O OptaPlanner criará o estado inicial aleatoriamente (pode ser inviável), calculará a função de adequação das regras e até operará os swaps de acordo com o algoritmo de otimização. Você pode escolher e ajustar parâmetros como agendamento de recozimento.
Jesvin Jose

6

Algoritmos genéticos se aplicam aqui. Durante meu curso de graduação, um de meus colegas escreveu um artigo para um problema muito semelhante ao seu.

Você pode procurar o Job Shop Scheduling e também o Open Shop Scheduling ou o Flow Shop Scheduling podem ser pontos de partida interessantes

Para usar um algoritmo genético, você não precisa de uma solução perfeita, pode começar com N candidatos aleatórios e aplicar uma função de adequação a cada um deles, por exemplo:

  • A diferença de noites atribuídas entre o médico mais ocupado e o menos ocupado trabalhado é uma penalização na função de custo
  • Cada vez que um médico trabalha mais de 5 dias por semana ou 1 noite por semana, você aplica uma penalidade
  • Cada uma de suas restrições, etc ...

Ao gerar N candidatos, você escolheria o melhor X , eles seriam os que infligiriam as restrições menos. Trabalhando com eles, cruzando e mutando ao longo de várias gerações, pode-se acabar com uma boa solução.

Tendo falado tudo isso, toda vez que eu usava um algoritmo genético que se baseava mais na mutação do que no cruzamento, eu desenvolvia um recozimento simulado que teria um desempenho muito melhor, com uma implementação mais fácil. O custo / adequação e a função de mutação para o algoritmo genético provavelmente serão muito semelhantes aos usados ​​em um recozimento simulado. Gostaria de começar por aí, veja a resposta de @Konrad Morawski

A pesquisa do Google encontra bons resultados para Job Shop e GA

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.