PES Pesquisa Operacional

Prof. Milton Procópio de Borba

Originais do Prof. Fernando Deeke Sasse

 

5. Programação Linear: Solução pelo Método Simplex

5.1 Problema da produção de brinquedos: solução manual

Vamos agora estudar os passos do método simplex resolvendo o problema de produção de brinquedos. Tínhamos nesse o seguinte sistema de equações:

> restart:

> with(linalg):

Warning, the protected names norm and trace have been redefined and unprotected

> System:=[x[1]+x[3]=90, x[2]+x[4]=60, 5*x[1]+6*x[2]+x[5]=600];

System := [x[1]+x[3] = 90, x[2]+x[4] = 60, 5*x[1]+6...

> A:=genmatrix(System,[x[1],x[2],x[3],x[4],x[5]],RHS);

A := matrix([[1, 0, 1, 0, 0], [0, 1, 0, 1, 0], [5, ...

> b:=evalm(RHS);

b := vector([90, 60, 600])

> c:=vector(5,[30,40,0,0,0]);

c := vector([30, 40, 0, 0, 0])

Vamos agora definir uma matriz básica B a partir de A, usando a últimas três colunas (matriz identidade) :

> for j to 5 do a[j]:=col(A,j) od;

a[1] := vector([1, 0, 5])

a[2] := vector([0, 1, 6])

a[3] := vector([1, 0, 0])

a[4] := vector([0, 1, 0])

a[5] := vector([0, 0, 1])

> B:=augment(a[3],a[4],a[5]);

B := matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

A solução básica é então dada por

> xB:=evalm((1/B)&*b);

xB := vector([90, 60, 600])

Ou seja, se x[1] = x[2] = 0, então x[3] = 90 , x[4] = 60 e x[5] = 600 , de modo que se nada é produzido, então haverá uma capacidade ociosa de 90 e 60 unidades nos departamentos de carros e trens, respectivamente. Sem produção as 600 partes também não serão usadas. Isso corresponde à origem do gráfico.


[Maple Plot]

À solução básica xB está associada o vetor cB de preço associado às variáveis básicas. Como as outras variáveis estão zeradas, o valor da função objetivo é dado por z = cB*xB . Aqui cB pode ser considerado uma matriz linha e xB uma matriz coluna. No presente caso,

> cB:=vector(3,[c[3],c[4],c[5]]);

cB := vector([0, 0, 0])

> z:=evalm(cB&*xB);

z := 0

Como a matriz base B consiste de vetores linearmente independentes b[1], b[2], b[3] , ... , b[m] , qualquer coluna a[j] da matriz de coeficientes pode ser escrita como uma combinação linear das colunas de B. Ou seja,

a[j] = sum(y[ij]*b[i]) = B*y[j] ,

onde

y[j] = ( y[1*j], y[2*j] , ... , y[mj] ) '

é uma matriz coluna. Para computar estes coeficientes da combinação linear devemos fazer

> y[1]:=evalm((1/B)&*a[1]);

y[1] := vector([1, 0, 5])

> y[2]:=evalm((1/B)&*a[2]);

y[2] := vector([0, 1, 6])

Podemos agora definir um novo escalar:

z[j] = sum(y[ij]*cB[i],i = 1 .. m) = cB y[j] .

Esta quantidade é interpretada como o decréscimo no valor da função objetivo que resultará se uma unidade de uma variável não-básica x[j] for trazida à solução. No nosso caso temos

> z[1]:=evalm(cB &* y[1]);

z[1] := 0

> z[2]:=evalm(cB &* y[2]);

z[2] := 0

Devemos agora decidir como melhorar a presente solução. Para isso definimos c[j]-z[j] como sendo a contribuição resultante da introdução de uma unidade da variável não-básica x[j] na solução. O x[j] que dá o maior c[j]-z[j] é escolhido como a nova variável básica (os casos de "empate" podem ser decididos arbitrariamente). No presente caso temos

> c[1]-z[1]; c[2]-z[2];

30

40

Portanto deve entrar a coluna a[2] .

Devemos decidir agora qual a coluna da matriz básica que deve sair. Isso deve ser feito de modo que a nova solução básica seja factível. Já vimos que a coluna b[r] da matriz base que deve ser substituída pela coluna a[j] é aquela que satisfaz a

xB[r]/y[rj] = min[i] xB[i]/y[ij] , 0 < y[ij]

No nosso caso,

> if y[2][1]>0 then print(xB[1]/y[2][1]) else print("Não definido") fi;

> if y[2][2]>0 then print(xB[2]/y[2][2]) else print("Não definido") fi;

60

> if y[2][3]>0 then print(xB[3]/y[2][3]) else print("Não definido") fi;

100

Note, para evitar confusões, que o primeiro índice de y[i][j] é de colunas e o segundo é de linhas, ao contrário do usual, pois y[i] já denota um vetor coluna. Da relação acima vemos que o índice i = 2 deve ser selecionado. Ou seja, sai a coluna b[2] = a[4] .

A nova matriz básica agora é

> B:=augment(a[3],a[2],a[5]);

B := matrix([[1, 0, 0], [0, 1, 0], [0, 6, 1]])

O processo agora repete-se iterativamente:

> xB:=evalm(inverse(B) &* b);

xB := vector([90, 60, 240])

> cB:=vector(3,[c[3],c[2],c[5]]);

cB := vector([0, 40, 0])

> z:=evalm(cB &* xB);

z := 2400

> y[1]:=evalm(inverse(B) &* a[1]);
y[3]:=evalm(inverse(B) &* a[3]);

y[1] := vector([1, 0, 5])

y[3] := vector([1, 0, 0])

> z[1]:=evalm(cB &* y[1]);
z[3]:=evalm(cB &* y[3]);

z[1] := 0

z[3] := 0

> c[1]-z[1]; c[3]-z[3];

30

0

> # a[1] entra

> if y[1][1]>0 then print(xB[1]/y[1][1]) else print("No Ratio") fi;

90

> if y[1][2]>0 then print(xB[2]/y[1][2]) else print("No Ratio") fi;

> if y[1][3]>0 then print(xB[3]/y[1][3]) else print("No Ratio") fi;

48

> # b[3]=a[5] sai

> B:=augment(a[3],a[2],a[1]);

B := matrix([[1, 0, 1], [0, 1, 0], [0, 6, 5]])

> xB:=evalm(inverse(B) &* b);

xB := vector([42, 60, 48])

> cB:=vector(3,[c[3],c[2],c[1]]);

cB := vector([0, 40, 30])

> z:=evalm(cB &* xB);

z := 3840

> y[4]:=evalm(inverse(B) &* a[4]);
y[5]:=evalm(inverse(B) &* a[5]);

y[4] := vector([6/5, 1, -6/5])

y[5] := vector([-1/5, 0, 1/5])

> z[4]:=evalm(cB &* y[4]);
z[5]:=evalm(cB &* y[5]);

z[4] := 4

z[5] := 6

> c[4]-z[4]; c[5]-z[5];

-4

-6

> # Solução ótima

A solução ótima foi encontrada pois a introdução de qualquer variável não básica na base diminuiria o valor da função objetivo. Portanto

> x[2]:=xB[2];

x[2] := 60

> x[1]:=xB[3];

x[1] := 48

e o lucro é

> z:=evalm(cB &* xB);

z := 3840

Ver em Excel ( este problema dos brinquedos e das Duas Minas por SIMPLEX )

5.2 Problema da produção de brinquedos: solução com pacote simplex

> restart:

> with(simplex):

Warning, the protected names maximize and minimize have been redefined and unprotected

> z:=30*x[1]+40*x[2];

z := 30*x[1]+40*x[2]

> rest[1]:=x[1]<=90; rest[2]:=x[2]<=60; rest[3]:=5*x[1]+6*x[2]<=600;

rest[1] := x[1] <= 90

rest[2] := x[2] <= 60

rest[3] := 5*x[1]+6*x[2] <= 600

> Sol:=maximize(z,{seq(rest[i],i=1..3)},NONNEGATIVE);

Sol := {x[1] = 48, x[2] = 60}

> assign(Sol); z;

3840


Ver em
Excel ( este problema dos brinquedos e das Duas Minas por SIMPLEX )

5.3 Exercício

Resolva o seguinte problem de PL utilizando o método manual e depois confira o resultado usando o pacote simplex.

min z := 2*x[1]+4*x[2]

x[1]+5*x[2] <= 80

20 <= 4*x[1]+2*x[2]

x[1]+x[2] = 10

Sugestão: transforme o problema de minimização de z em um problema de maximização para -z .

Solução manual

Introduzindo a variável de folga x[3] e x[4] as desiguladades acima tornam-se:

x[1]+5*x[2]+x[3] = 80

4*x[1]+2*x[2]-x[4] = 20

x[1]+x[2] = 10 .

A matriz de coeficientes é A = matrix([[1, 5, 1, 0], [4, 2, 0, -1], [1, 1, 0, ... . Neste ponto não é claro qual é a matriz base que devemos escolher de modo que a primeira solução básica seja factível, com exisgido no método simplex. Introduzimos então duas novas variáveis artificiais x[5] e x[6] nas últimas equações:

x[1]+5*x[2]+x[3] = 80 ,

4*x[1]+2*x[2]-x[4]+x[5] = 20 ,

x[1]+x[2]+x[6] = 10 .

A matrix de coeficientes é agora dada por

A = matrix([[1, 5, 1, 0, 0, 0], [4, 2, 0, -1, 1, 0]...

Portanto, a primeira matrix básica que vai gerar uma solução básica factível é A = [a[3], a[5], a[6]] , de modo que x[b] = [80, 20, 10] . As variáveis artificiais devem ser eliminadas no final. Para garantir que na solução ótima elas sejam zero, devemos associa-las a um preço muito alto. Para isso reescrevemos a função objetivo como

min z = 2*x[1]+4*x[2] + 0 x[3] + 0 x[4] + M*x[5]+M*x[6] ,

onde M é um número não-negativo que é assumido ser suficientemente grande de modo a garantir que qualquer preço correspondente a uma variável legítima seja desprezível com relação a M . Podemos ainda transformar o problema de minimização em maximização, trocando o sinal da função objetivo:

max -z = -2*x[1] - 4*x[2] - M*x[5]-M*x[6] .

Vamos então proceder à solução do problema.

> restart:

> with(linalg):

Warning, new definition for norm

Warning, new definition for trace

> A := matrix([[1, 5, 1, 0, 0, 0], [4, 2, 0, -1, 1, 0], [1, 1, 0, 0, 0, 1]]);

A := matrix([[1, 5, 1, 0, 0, 0], [4, 2, 0, -1, 1, 0...

> c:=[-2,-4,0,0,-M,-M];

c := [-2, -4, 0, 0, -M, -M]

> b:=[80,20,10];

b := [80, 20, 10]

> for j to 6 do a[j]:=col(A,j) od;

a[1] := vector([1, 4, 1])

a[2] := vector([5, 2, 1])

a[3] := vector([1, 0, 0])

a[4] := vector([0, -1, 0])

a[5] := vector([0, 1, 0])

a[6] := vector([0, 0, 1])

> B:=augment(a[3],a[5],a[6]);

B := matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

> xB:=evalm(B^(-1)&*b);

xB := vector([80, 20, 10])

> cB:= [c[3],c[5],c[6]];

cB := [0, -M, -M]

> z:=evalm(cB&*xB);

z := -30*M

> for j from 1 to 2 do

> y[j]:=evalm(B^(-1)&*a[j]);

> od;

y[1] := vector([1, 4, 1])

y[2] := vector([5, 2, 1])

> y[4]:=evalm(B^(-1)&*a[4]);

y[4] := vector([0, -1, 0])

> for j from 1 to 2 do

> z[j]:=evalm(cB&*y[j]);

> od;

z[1] := -5*M

z[2] := -3*M

> z[4]:=evalm(cB&*y[4]);

z[4] := M

> for j from 1 to 2 do

> l[j]:=c[j]-z[j];

> od;

l[1] := -2+5*M

l[2] := -4+3*M

> l[4]:=c[4]-z[4];

l[4] := -M

Como estamos assumindo que M é muito grande, só ele conta. Isso significa que a[1] deverá entrar para a matriz básica.

> for i from 1 to 3 do

> if y[1][i]>0 then print(evalf(xB[i]/y[1][i])) else print(impossivel) fi;

> od;

80.

5.

10.

Portanto, sai b[2] = a[5] . A nova matriz base é

> B:=augment(a[3],a[1],a[6]);

B := matrix([[1, 1, 0], [0, 4, 0], [0, 1, 1]])

> xB:=evalm(B^(-1)&*b);

xB := vector([75, 5, 5])

> cB:= [c[3],c[2],c[6]];

cB := [0, -4, -M]

> z:=evalm(cB&*xB);

z := -20-5*M

> y[1]:=evalm(B^(-1)&*a[1]);

y[1] := vector([0, 1, 0])

> y[4]:=evalm(B^(-1)&*a[4]);

y[4] := vector([1/4, -1/4, 1/4])

> y[5]:=evalm(B^(-1)&*a[5]);

y[5] := vector([-1/4, 1/4, -1/4])

> z[1]:=evalm(cB&*y[1]);

z[1] := -4

> z[4]:=evalm(cB&*y[4]);

z[4] := 1-1/4*M

> z[5]:=evalm(cB&*y[5]);

z[5] := -1+1/4*M

> l[1]:=c[1]-z[1];

l[1] := 2

> l[4]:=c[4]-z[4];

l[4] := -1+1/4*M

> l[5]:=c[5]-z[5];

l[5] := -5/4*M+1

>

Portanto, entra a[4] .

> for i from 1 to 3 do

> if y[4][i]>0 then print(evalf(xB[i]/y[4][i])) else print(impossivel) fi;

> od;

300.

impossivel

20.

>

Sai b[3] = a[6] .

> B:=augment(a[3],a[1],a[4]);

B := matrix([[1, 1, 0], [0, 4, -1], [0, 1, 0]])

> xB:=evalm(B^(-1)&*b);

xB := vector([70, 10, 20])

> cB:= [c[3],c[1],c[4]];

cB := [0, -2, 0]

> z:=evalm(cB&*xB);

z := -20

> y[2]:=evalm(B^(-1)&*a[2]);

y[2] := vector([4, 1, 2])

> y[5]:=evalm(B^(-1)&*a[5]);

y[5] := vector([0, 0, -1])

> y[6]:=evalm(B^(-1)&*a[6]);

y[6] := vector([-1, 1, 4])

> z[2]:=evalm(cB&*y[2]);

z[2] := -2

> z[5]:=evalm(cB&*y[5]);

z[5] := 0

> z[6]:=evalm(cB&*y[6]);

z[6] := -2

> l[2]:=c[2]-z[2];

l[2] := -2

> l[5]:=c[5]-z[5];

l[5] := -M

> l[6]:=c[6]-z[6];

l[6] := -M+2

Chegamos então à solução ótima, com x[1] = 10 , x[2] = 0 e z = 20 .