Proposta de Mini-Curso para a XLIII SBPO Artur Alves Pessoa Eduardo Uchoa Departamento de Engenharia de Produção Universidade Federal Fluminense Título: UFFLP: Integrando Programação Inteira Mista e Planilhas de Cálculo Um problema de Programação Linear Inteira consiste em atribuir valores inteiros a variáveis, satisfazendo restrições lineares de modo a maximizar ou minimizar uma função objetivo linear. Quando uma ou mais variáveis podem assumir valores fracionários, o problema é denominado Programação Inteira Mista (PIM), omitindo-se o adjetivo Linear. Os primeiros algoritmos para se resolver problemas de PIM surgiram no final dos anos 50 [Gomory, 1958] e início dos anos 60 [Land e Doig, 1960]. Após mais de 50 anos de PIM, com a evolução da capacidade de processamento dos computadores e o desenvolvimento de inúmeras técnicas capazes de melhorar a eficiência dos algoritmos existentes [Wolsey, 1998], diversos problemas de otimização de larga escala já podem ser resolvidos de forma exata. Além disso, a existência de diversos softwares comerciais e acadêmicos para a resolução de problemas de PIM tornou esta tecnologia acessível a engenheiros, economistas, administradores e outros profissionais que possam identificar problemas de otimização relevantes em suas respectivas áreas de atuação. Apesar disso, a utilização efetiva desta tecnologia ainda requer que o profissional seja capaz de realizar duas tarefas principais: 1. O problema genérico deve ser modelado na forma de variáveis inteiras ou contínuas e restrições lineares. Essa tarefa é feita no papel, usando simbologia matemática: somatórios, conjuntos, matrizes, etc. 2. A partir dos dados primários de uma instância particular do problema, deve ser gerado o PIM específico correspondente, para que esse possa ser lido por um resolvedor de PIM. Da mesma forma, a solução fornecida pelo resolvedor de PIM em termos de valores de variáveis deve ser traduzida para o contexto do problema original. Mesmo para instâncias de pequeno ou médio porte, é altamente recomendado que essa tarefa seja automatizada. Apesar da tarefa 1 aparentemente requerer um esforço intelectual maior, a tarefa 2 é muitas vezes a maior barreira enfrentada por iniciantes. Isto ocorre porque os cursos de pesquisa operacional freqüentemente omitem essa segunda etapa, exigindo apenas que o aluno construa um PIM particular para uma única instância (sempre pequena) do problema. Tipicamente isso é feito no editor de textos de ferramentas como o LINDO [LINDO Systems, 2010]. A automatização da construção de PIMs, no entanto, requer o uso de linguagens de programação. Neste contexto, softwares comerciais como o
CPLEX [IBM, 2010a], o XPRESS [FICO, 2010] ou o próprio LINDO dispõem de linguagens e/ou interfaces de programação (API s) voltadas para o desenvolvimento de aplicações que utilizam resolvedores de PIM como subrotinas. Dentre estas linguagens e interfaces estão o CONCERT [IBM, 2010b], o AMPL [Fourer e outros, 2002] e o XPRESS-MOSEL. Apesar disso, não é do conhecimento dos autores deste mini-curso que alguma destas linguagens ou interfaces seja amplamente utilizada por alunos de engenharia em universidades brasileiras, possivelmente devido à limitação de disponibilidade gratuita para uso acadêmico, devido à resistência ao aprendizado de uma nova linguagem de programação ou devido à dificuldade na obtenção de suporte. Para suplantar estas dificuldades, a biblioteca de funções UFFLP foi criada há mais de três anos a partir da observação de que as planilhas de cálculo modernas, que são amplamente utilizadas num grande número de empresas, possuem linguagens de programação poderosas que permitem a realização da tarefa 2. Apesar de softwares como o CONCERT, o AMPL e o MOSEL permitirem a importação e exportação de dados de planilhas de cálculo, a possibilidade manipular os dados de entrada, construir um PIM particular, resolvê-lo e visualizar a solução no mesmo ambiente, torna o uso da UFFLP bem mais prático. A UFFLP é uma Dynamic Link Library (DLL) para Windows que pode ser chamada de programas escritos em Visual Basic for Applications (VBA) dentro da planilha de cálculo Excel [Microsoft, 2010]. Vale mencionar que o Excel/VBA já tem funções de resolução de problemas de PIM integradas. No entanto, o desempenho dessas funções não é competitivo com o de resolvedores especializados como o CBC [COIN-OR, 2010] ou o CPLEX. As funções da UFFLP também podem ser chamadas de programas em C/C++ a partir do Windows ou do Linux. A UFFLP tem ainda as seguintes funcionalidades: 1. Referência a variáveis e restrições do modelo PIM apenas pelos seus nomes (strings). 2. Possibilidade de integração com heurísticas e rotinas de geração de cortes chamadas através de callbacks em VBA ou em C/C++. 3. Pode utilizar como resolvedor tanto o Coin-CBC (totalmente aberto e gratuito) e o CPLEX (fechado, gratuito apenas para uso acadêmico). 4. Código fonte aberto e gratuito, disponível em http://www.logis.uff.br/~artur/ufflp A UFFLP já foi utilizada com sucesso em três edições do curso de nível de pósgraduação Modelagem em Logística, onde boa parte dos alunos são engenheiros com pouco conhecimento de programação. A biblioteca também foi utilizada em dois trabalhos de conclusão de curso [Rezende e Azevedo, 2008] e [Torres e Azevedo, 2009] e em duas dissertações de mestrado [Gonçalves, 2009] e [Aizemberg, 2010], e atualmente vem sendo utilizada em dois trabalhos de tese de doutorado e em um projeto de pesquisa financiado pela Petrobras. Um exemplo ilustrativo de uso da UFFLP é fornecido no apêndice.
Este mini-curso pretende apresentar a UFFLP como uma alternativa para a automatização da construção de modelos de PIM que seja atraente para estudantes, profissionais e professores com pouca experiência no uso de linguagens de programação e uma ferramenta de prototipação rápida no caso de usuários que já possuem experiência no uso destas ferramentas. Ementa I Programação em Excel/VBA e funções básicas da UFFLP Inclusão de rotinas de programação em planilhas de cálculo Instalação da UFFLP Criação de modelos de PIM usando UFFLP Resolução e recuperação da solução usando UFFLP Exemplos II Automatização da entrada e saída de dados e correção de erros Leitura e escrita de dados da planilha de cálculo Visualização gráfica da solução Estudo de caso detalhado: problema do caixeiro viajante Uso do depurador do Excel Interpretação do arquivo de log do resolvedor de PIM III Funções avançadas da UFFLP Callback de geração de cortes Estudo de caso detalhado: problema de localização de facilidades Callback de heurísticas primais Estudo de caso detalhado: problema de escalonamento open shop. Referências L. Aizemberg, Modelos de Programação Inteira Mista e Heurísticas para Otimização da Produção de Computadores no Ambiente do Jogo TAC/SCM Mestrado em Engenharia de Produção - Universidade Federal Fluminense, 2010. Computational Infrastructure for Operations Research COIN-OR, CBC Project, URL: http://www.coin-or.org/projects/cbc.xml, 2010 FICO, FICO Xpress Optimization Suite 7, URL: http://www.fico.com/en/products/ DMTools/Pages/FICO-Xpress-Optimization-Suite.aspx, 2010 R. Fourer, D. M. Gay e B. W. Kernighan, AMPL: A Modeling Language for Mathematical Programming Brooks/Cole Publishing Company, 2002
R. E. Gomory, Outline of an algorithm for integer solutions to linear programs Bulletin of the American Mathematical Society 64 (5), 275-278, 1958. J. M. B. Gonçalves, Formulações para o Problema do Flow Shop em Duas Máquinas com Penalidades por Atraso nas Tarefas Mestrado em Engenharia de Produção - Universidade Federal Fluminense, 2009. International Business Machines IBM, IBM ILOG CPLEX Optimizer, URL: http://www-01.ibm.com/software/integration/optimization/cplex-optimizer/, 2010a International Business Machines IBM, IBM ILOG CPLEX Optimization Studio Interfaces, URL: http://www-01.ibm.com/software/integration/optimization/cplex/ interfaces/, 2010b A. H. Land e A. G. Doig, An Automatic Method of Solving Discrete Programming Problems Econometrica 28 (3), 497-520, 1960. LINDO Systems, Optimization Software: Integer Programming, Linear Programming, Nonlinear Programming, Global Optimization, URL: http://www.lindo.com/, 2010 Microsoft, Microsoft Office Excel, http://office.microsoft.com/pt-br/excel/ fx100646961046.aspx, 2010 F. F. Rezende e F. M. de Azevedo, Problema de Roteirização de Veículos na Cadeia de Logística Reversa da Indústria de Pneus Trabalho de Conclusão de Curso, Engenharia de Produção - Universidade Federal Fluminense, 2008. C. R. R. Torres e G. H. I. de Azevedo, Problemas de Escalonamento de Projetos com Restrição de Recursos: um Estudo de Caso no Setor de Petróleo e Gás Trabalho de Conclusão de Curso, Engenharia de Produção - Universidade Federal Fluminense, 2009. L. A. Wolsey, Integer Programming Wiley-Interscience, 1998. Apêndice Para ilustrar o uso da UFFLP, esta seção descreve um aplicativo de otimização do problema clássico conhecido Problema das p-medianas, desenvolvido em VBA no ambiente do Excel. Este problema é de ampla aplicação em diversas áreas do conhecimento, sendo particularmente muito usado em aplicações de Logística. O problema é definido da seguinte forma. Dados n clientes e m locais, deseja-se escolher exatamente p locais e atribuir cada cliente a exatamente um local escolhido de modo a minimizar a soma das distâncias dos clientes aos locais aos quais eles foram atribuídos. Na sua versão euclidiana, são dadas as coordenadas X e Y da posição de cada cliente e de cada local no plano, e a distância dist(i,j) do cliente i, posicionado em (X i, Y i ), ao local j, posicionado em (X j+n, Y j+n ), é distância euclidiana entre respectivas posições, dada por ( X X ) + ( Y Y ). Para este problema, é utilizada a seguinte formulação: 2 2 j+ n i j+ n i
Variáveis: x j y ij quando 1 indica que o local j foi escolhido. É zero em caso contrário. quando 1 indica que o cliente i é atribuído ao local j. É zero em caso contrário. Restrições: Minimizar Sujeito a n m dist( i, j) yij (0) i= 1 j= 1 m yij = 1, i = 1,..., n (1) j= 1 y ij x, i = 1,..., n; j = 1,..., m (2) j m x j = p (3) j= 1 x {0,1}, j = 1,..., m (4) j y {0,1}, i = 1,..., n; j = 1,..., m (5) ij A função objetivo (0) contabiliza os custos associados às distâncias dos clientes aos locais aos quais foram atribuídos. As restrições (1) garantem que cada cliente á atribuído a exatamente 1 local. As restrições (2) só permitem atribuir clientes a locais abertos. A restrição (3) permite abrir apenas p locais. Por fim, as restrições (4) e (5) definem os domínios das variáveis. Figura 1: Instância Euclidiana do Problema das p-medianas na planilha de cálculo
O aplicativo desenvolvido permite resolver qualquer instância do problema a partir dos dados de entrada primários da instância (n, m, p, as coordenadas dos clientes e dos locais) e visualizar o resultado graficamente através da planilha de cálculo. A Figura 1 mostra os dados de entrada de uma instância denominada Teste1 organizados numa folha da planilha. É possível trabalhar com diversas instâncias ao mesmo tempo, cada instância em uma folha separada. Figura 2: Solução do Problema das p-medianas Euclidiano na planilha de cálculo A Figura 2 mostra o nome da instância selecionada para resolução, o botão Resolve, que ativa a resolução, a lista de locais abertos na solução ótima, o valor da função objetivo e um desenho da solução obtida. No desenho, os círculos azuis representam clientes, as linhas azuis ligam os clientes aos locais a que foram atribuídos, os quadrados vermelhos são locais abertos e os quadrados cinza são os locais fechados. Usando a UFFLP a partir do VBA/Excel a função objetivo e as variáveis y ij e x j são criadas pelo Código Fonte 1. Neste código, As chamadas à UFFLP são indicadas pelo prefixo UFFLP_ encontrado nos nomes das funções. Os resultados das chamadas, que são armazenados na variável erro, indicam sucesso se forem zero ou fornecem um código de erro. Os valores de X i, Y i, X j+n e Y j+n são armazenados em Clientes(i,1), Clientes(i,2), Locais(j,1) e Locais(j,2), respectivamente. Além disso, o símbolo & indica a concatenação de cadeias de caracteres (strings).
' Cria uma instância de PIM na UFFLP problema = UFFLP_CreateProblem ' Variáveis "y_i_j": binárias onde 1 indica que o cliente i é atendida no local j For i = 1 To n ' calcula dist(i,j) dist = Sqr((Clientes(i, 1) - Locais(j, 1)) ^ 2 + _ (Clientes(i, 2) - Locais(j, 2)) ^ 2) ' Cria a variável "y_i_j" com custo "dist(i,j)" variavel = "y_" & i & "_" & j erro = UFFLP_AddVariable_(problema, variavel, 0, 1, dist, UFFLP_Binary) ' Variáveis "x_j": binárias onde 1 indica o local j está aberto ' Cria a variável "x_j" com custo zero variavel = "x_" & j erro = UFFLP_AddVariable_(problema, variavel, 0, 1, 0, UFFLP_Binary) Código Fonte 1: Criação das variáveis pela UFFLP para o Problema das p-medianas As restrições (1), (2) e (3) são criadas, nesta ordem, pelo Código Fonte 2. O código fonte completo do aplicativo tem apenas 315 linhas, incluindo a visualização gráfica. Nos cursos oferecidos nos últimos 3 anos foi observado que uma vez que os alunos se familiarizem com alguns exemplos simples do uso da UFFLP, como este da p-mediana, eles se tornam capazes de implementar de forma independente modelos bem mais complexos.
' Para cada cliente i, "Soma(j=1..m) y_i_j = 1" For i = 1 To n ' Acrescenta a restrição do cliente i restricao = "Cliente_" & i ' Soma o termo "y_i_j" ao lado esquerdo da restrição variavel = "y_" & i & "_" & j erro = UFFLP_SetCoefficient_(problema, restricao, variavel, 1) ' Completa a restrição com "= 1" erro = UFFLP_AddConstraint_(problema, restricao, 1, UFFLP_Equal) ' Para cada cliente i e cada local j, "y_i_j - x_j <= 0" For i = 1 To n ' Acrescenta de abertura do local j para o cliente i restricao = "Abertura_" & j & "_" & i ' Soma o termo "y_i_j" ao lado esquerdo da restrição variavel = "y_" & i & "_" & j erro = UFFLP_SetCoefficient_(problema, restricao, variavel, 1) ' Soma o termo "-x_j" ao lado esquerdo da restrição variavel = "x_" & j erro = UFFLP_SetCoefficient_(problema, restricao, variavel, -1) ' Completa a restrição com "<= 0" erro = UFFLP_AddConstraint_(problema, restricao, 0, UFFLP_Less) ' "Soma(j=1..m) x_j = p" ' Acrescenta a restrição das p medianas restricao = "pmedianas" ' Soma o termo "x_j" ao lado esquerdo da restrição variavel = "x_" & j erro = UFFLP_SetCoefficient_(problema, restricao, variavel, 1) ' Completa a restrição com "= p" erro = UFFLP_AddConstraint_(problema, restricao, p, UFFLP_Equal) Código Fonte 2: Criação das restrições pela UFFLP para o Problema das p-medianas