5.3 Um algoritmo exato para encontrar a solução do problema com variáveis binárias
5.3.3 O método Branch-and-Bound implícito
O algoritmo Branch-and-Bound implícito resolve problemas quadráticos do tipo min 1 2𝑥 𝑇𝑄𝑥+ 𝑐𝑇𝑥 𝑆.𝑎 𝐴𝑥 ≤ 𝑏 𝐶𝑎𝑟𝑑(𝑛𝑧(𝑥)) ≤ 𝐾 𝑥𝑖 ≥ 𝑙𝑖,𝑖 ∈ 𝑛𝑧(𝑥) 𝑥𝑖 = 0,𝑖 /∈ 𝑛𝑧(𝑥), (5.11)
que pode ser entendido como a versão geral do Problema (2.6), apresentado na Seção 2.4, ou uma formulação alternativa do Problema (5.1).
A principal diferença entre essa formulação e a de um problema de programação quadrática 0-1 convencional é que as variáveis binárias estão implícitas, ou seja, não aparecem, mas são necessárias para que tenhamos no máximo 𝐾 variáveis positivas, ou seja, para que
𝐶𝑎𝑟𝑑(𝑛𝑧(𝑥)) ≤ 𝐾. (5.12)
Essa forma implícita de tratar as variáveis binárias pode ser estendida ao método Branch-and-
Bound para variáveis 0-1. Neste caso, eliminamos do problema relaxado (o nó raiz da árvore
binária) a Restrição (5.12) e os limites
𝑥𝑖 ≥ 𝑙𝑖, 𝑖 ∈ 𝑛𝑧(𝑥)
𝑥𝑖 = 0, 𝑖 /∈ 𝑛𝑧(𝑥),
(5.13)
adotando apenas a restrição de não negatividade 𝑥 ≥ 0.
Obtemos, assim, um problema clássico de programação quadrática, na forma (5.8). A única diferença entre este problema e o correspondente ao nó raiz do Branch-and-Bound usual é a
inexistência da restrição ∑︀𝑛 𝑖=1
𝑧𝑖 ≤ 𝐾 presente na formulação (5.1), mas não em (5.11).
A relaxação das restrições de integralidade das variáveis binárias, permite que a cardinalidade de nz(x) seja superior a K e que as componentes estritamente positivas do vetor x assumam valores abaixo de seus limites inferiores. No caso provável da solução do nó raiz da árvore não satisfazer as restrições (5.12) ou (5.13), é necessário ramificar uma variável qualquer. É justamente na manipulação das ramificações que as restrições ignoradas são levadas em conta, justificando o caráter implícito do método Branch-and-Bound.
A ideia é fazer com que, a cada ramificação, as variáveis estejam mais próximas de obedecer às restrições de cardinalidade e limite inferior. Usualmente, a ramificação do método Branch-
and-Bound é feita sobre as variáveis binárias, 𝑧𝑖. Porém, nessa formulação, essas variáveis estão
definidas de forma implícita, de forma que a ramificação também será feita desse jeito, considerando os efeitos que a ramificação de uma variável binária 𝑧𝑖, provoca sobre a sua variável real associada,
𝑥𝑖. Vejamos como ramificar, de maneira implícita, uma variável 𝑧𝑠:
• Habitualmente, a ramificação para baixo corresponde à atribuição do valor 0 à variável binária associada a 𝑥𝑠, obrigando-nos a adotar 𝑥𝑠 = 0. No método implícito, essa ramificação é obtida
por meio da eliminação direta de 𝑥𝑠, o que provoca a geração de um novo subproblema com
uma variável a menos. Esse subproblema é resolvido pelo do método de Lemke.
• No problema financeiro usual, a ramificação para cima está relacionada à inclusão forçada de um ativo na carteira. No Branch-and-Bound para problemas 0-1, isso equivale a atribuir o valor 1 à variável binária associada à variável 𝑥𝑠, ao passo que, no Branch-and-Bound
implícito, tal exigência se resume à inclusão da restrição 𝑥𝑠≥ 𝑙𝑠. Esse tipo de ramificação traz
consequências não só à restrição de limite inferior, mas também à restrição de cardinalidade, que pode passar a ser infactível. No método implícito, essa ramificação é feita apenas quando
𝑥𝑠 é estritamente positiva e está abaixo do seu limite inferior 𝑙𝑠. Neste caso, incluímos no
problema a restrição 𝑥𝑠 ≥ 𝑙𝑠 e o resolvemos pelo método de Lemke. Para evitar que a
Restrição (5.12) se torne infactível, a ramificação para cima não é feita se o número de variáveis ramificadas para cima for superior ou igual a K.
É possível observar que o problema gerado pelas ramificações é muito parecido com o original, em geral diferindo apenas por uma restrição ou pelo número de variáveis. Dessa forma, a solução do problema que gera as ramificações é ótima para os problemas ramificados, porém infactível. Como o método de Lemke resolve problemas de complementaridade linear, fica evidente que, partindo de soluções infactíveis, ele pode resolver o problema gerado pelas ramificações em poucos passos, já que a solução inicial é quase ótima, gerando um processo que é conhecido como warm-start.
Para facilitar a compreensão da versão implícita do Branch-and-Bound, apresentamos os passos que compõem o algoritmo (que chamaremos de Algoritmo BBI ) por meio de um pseudocódigo que está ilustrado no Algoritmo 5.
Algoritmo 5: O Algoritmo BBI
1 Utilizando o método de Lemke, resolva o problema relaxado, retirando as Restrições (5.12) e
(5.13);
2 se na solução obtida, não tivermos mais que 𝐾 variáveis não nulas e se estas satisfizerem
as restrições de limite inferior, então
3 Pare, pois a solução do problema relaxado já é ótima; 4 senão
5 Escolha uma variável binária não inteira para ramificar;
6 Crie uma lista de nós pendentes, 𝑛𝑜𝑠𝑝, contendo os dois subproblemas gerados pela
ramificação;
7 𝑥* ←[ ] (vetor indefinido), 𝜁* ←+∞; 8 enquanto 𝑛𝑜𝑠𝑝 ̸= ∅ faça
9 Retire um subproblema de 𝑛𝑜𝑠𝑝;
10 Usando o método de Lemke, resolva esse subproblema, obtendo 𝑥 e 𝜁 ou a indicação
de que ele é infactível;
11 se 𝑥 possuir componentes não nulas menores que os limites inferiores
correspondentes ou se o número de componentes não nulas for maior que 𝐾, então
12 Escolha uma variável para ramificar;
13 Inclua em 𝑛𝑜𝑠𝑝 o problema relacionado à ramificação para baixo; 14 se a ramificação para cima não violar a Restrição (5.12), então 15 Inclua a ramificação para cima em nosp;
16 fim
17 senão
18 se 𝜁 < 𝜁*, então
19 𝑥* ← 𝑥 e 𝜁* ← 𝜁;
20 para todo nó 𝑖 de 𝑛𝑜𝑠𝑝 faça
21 se 𝜁𝑖𝑝 ≥ 𝜁*, onde 𝜁𝑖𝑝 é o valor da função objetivo do pai do nó 𝑖, então
22 Elimine o nó 𝑖 de 𝑛𝑜𝑠𝑝; 23 fim 24 fim 25 fim 26 fim 27 fim
28 A solução do problema é 𝑥*, com função objetivo igual a 𝜁*;
29 fim
1) e determinamos se sua solução é ótima (linha 2). Caso não o seja, o que é natural de se esperar, escolhemos uma variável para ramificar e criamos uma lista inicial de nós pendentes (linhas 5 e 6). Na linha 8, começamos a parte iterativa do método, que acaba quando todos os subproblemas relevantes forem resolvidos.
Em uma iteração qualquer, retiramos um subproblema da lista e o resolvemos pelo método de Lemke (linhas 9 e 10). Caso a solução obtida não for factível para o Problema (3.1), geramos, se possível, dois nós filhos, provenientes desse subproblema, e os incluímos na lista de nós pendentes (linhas 12 a 15). Senão, ela é inteira e factível para (3.1), de modo que podemos testar se a mesma é melhor que a atual. Nesse caso, atualizamos a solução do problema (linha 19) e eliminamos, de nossa lista, os nós filhos cujos pais são piores que ela (linhas 21 a 23).