# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# LCF586_R_ProgLinear.r
# ---------------------
# Projeto: Solução de problemas de programação linear usando o R
#
# Autor:   Luiz Carlos Estraviz Rodriguez
#
# Data:    16/Out/2018
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
rm(list=ls(all=TRUE))                                   # Limpa memória
gc()

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Enunciado do problema:
# Uma empresa produz dois modelos de cadeiras: 4P e 3P. O modelo 4P
# precisa de 4 pernas, 1 assento e 1 enconsto. Por outro lado, o modelo
# 3P precisa de 3 pernas e 1 assento. A empresa tem um estoque inicial
# de 200 pernas, 500 assentos e 100 encostos. Se a empresa precisar de
# mais pernas, assentos e enconstos, pode comprar blocos de madeira
# padrão, cujo custo é de 80 reais por bloco. A empresa pode produzir
# 10 assentos, 20 pernas e 2 encostos a partir de um bloco de madeira
# padrão. O custo de produção do modelo 4P é de 30 reais / cadeira,
# enquanto o custo do modelo 3P é de 40 reais / cadeira. Por fim, a
# empresa informa que o número mínimo de cadeiras para produzir é de
# 1.000 unidades por mês. Definir um modelo de programação linear, que
# minimize o custo total (os custos de produção dos dois modelos, e a
# quantidade necessária de novos blocos de madeira).


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Definição dos coeficientes e parâmetros do problema de PL
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Coeficientes das variáveis na função objetivo                    -> C
C <- c(30, 40, 80)
# Matrix de coeficientes técnicos das restrições                   -> A
A <- matrix(c(1, 1, -10,
              4, 3, -20,
              1, 0, -2,
              1, 1, 0), nrow=4, byrow=TRUE)
# Coeficientes do RHS (Right hand side) das restrições             -> B
B <- c(500, 200, 100, 1000)
# Direção de cada restrição
direcoes  <- c("<=", "<=", "<=", ">=")
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Solução usando o pacote lpSolve
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Carrega o pacote lpSolve
if(!require(lpSolve)){
        install.packages('lpSolve')
        require(lpSolve)
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Definição dos argumentos da função lp() para busca da solução ótima
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
solotima <-  lp(direction="min",              # problema de minimização
                objective.in = C,             # coef da f objetivo
                const.mat = A,                # coef téc das restrições
                const.dir = direcoes,         # direção das restrições
                const.rhs = B,                # valores do RHS
                all.int = T)                  # todas var são inteiras
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Mostra solução
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Chama status da solução: 0 = successo, 2 = inviável
print(solotima$status)
# Resgata solução, nomeia variáveis e exibe solução
melhor_sol <- solotima$solution
names(melhor_sol) <- c("x_4p", "x_3p", "x_w") 
print(melhor_sol)
# Confere valor da função objetivo
print(paste("Custo total: ", solotima$objval, sep=""))

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Solução usando com pacote lpSolveAPI
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Carrega o pacote lpSolveAPI
if(!require(lpSolveAPI)){
        install.packages('lpSolveAPI')
        require(lpSolveAPI)
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Definição dos coeficientes e parâmetros do problema de PL
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Nomeia o problema e define 4 restrições e 3 variáveis de decisão
lpprob <- make.lp(nrow = 4, ncol = 3)
# Define o tipo de problema
lp.control(lpprob, sense="min")
# Definição do tipo para cada variável de decisão
set.type(lpprob, 1:3, type=c("integer"))
# Definição dos coeficientes da função objetivo
set.objfn(lpprob, C)
# Acréscimo das restrições
add.constraint(lpprob, A[1, ], "<=", B[1])
add.constraint(lpprob, A[2, ], "<=", B[2])
add.constraint(lpprob, A[3, ], "<=", B[3])
add.constraint(lpprob, A[4, ], ">=", B[4])
# Mostra a matrix de entrada de dados do lpSolve
lpprob
# Resolve o problema de PL
solve(lpprob)
# Mostra os valores das variáveis de decisão
get.variables(lpprob)
# Mostra o valor da função objetivo
get.objective(lpprob)
# Obs: limites default das variáveis de decisão são c(0, 0, 0) e c(Inf, Inf, Inf)
get.bounds(lpprob)