# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## Exercício Aula  18 - Otimização com Restrições

import math
import matplotlib.pyplot as plt
import numpy as np
from sympy.solvers import solve
from sympy import Symbol
import pandas as pd
# %matplotlib inline

# # a) Problema de programação linear:

# <img src='proglin.JPG'>

# # b) Resolução gráfica:

# ## No gráfico abaixo, as linhas pontilhadas são restrições e a linha cheia é a função a ser maximizada (neste caso, o lucro).
# ## A linha pontilhada laranja é a restrição do estoque de matéria-prima.
# ## A linha pontilhada verde é a restrição do tempo de produção disponível, por semana.
# ## A linha pontilhada roxa é a restrição da capacidade de armazenamento do estoque.

# ## Para iniciar o problema, será assumido um lucro de 10k reais para analisar o comportamento. Assim, tem-se o seguinte gráfico:

# +
def f1(x):
    return 550 - x
def f2(x):
    return (40 - 0.04*x)/0.12
def f3(x):
    return (9500 - 20*x)/5
def f4(x):
    return 0
def lucro(x):
    return (10000-45*x)/20

x = Symbol('x')
x1, =  solve(f1(x)-f2(x))
x2, =  solve(f1(x)-f3(x))
x3, =  solve(f2(x)-f3(x))
x4, =  solve(f3(x)-f4(x))
x5 = 0
x6 = 0

y1 = f1(x1)
y2 = f1(x2)
y3 = f2(x3)
y4 = f3(x4)
y5 = 0
y6 = 333.333

plt.figure(figsize=(10,10))

plt.plot(x1,f1(x1),'go',markersize=5)
plt.plot(x2,f1(x2),'go',markersize=5)
#plt.plot(x3,f2(x3),'go',markersize=5)
plt.plot(x4,f4(x4),'go',markersize=5)
plt.plot(x5,y5,'go',markersize=5)
plt.plot(x6,y6,'go',markersize=5)

plt.fill([x1,x2,x3,x4,x5,x6,x1],[y1,y2,y3,y4,y5,y6,y1],'pink',alpha=0.5)

xr = np.linspace(0.5,550,100)
y1r = f1(xr)
y2r = f2(xr)
y3r = f3(xr)
ylucror = lucro(xr)

plt.plot(xr,y1r,'k--', color='yellowgreen', label='tempo útil para produção')
plt.plot(xr,y2r,'k--', color='mediumslateblue', label='armazenamento')
plt.plot(xr,y3r,'k--', color='darkorange', label='matéria-prima')
plt.plot(xr,ylucror, color='k', label='lucro')

plt.xlim(0,500)
plt.ylim(0,550)

plt.legend()
plt.show()


# -

# # O lucro é, neste gráfico, representado pela linha cheia. Desta forma, variando-se o valor do COEFICIENTE LINEAR DA RETA PRETA CHEIA (lucro) até encontrar a intersecção representada no gráfico com o ponto ótimo (que é aquele ponto ali mais à direita, onde duas retas pontilhadas se intersectam). Assim, pelo método gráfico, é possível concluir que o lucro máximo é de 22250 conforme o gráfico ABAIXO.

# +
def f1(x):
    return 550 - x
def f2(x):
    return (40 - 0.04*x)/0.12
def f3(x):
    return (9500 - 20*x)/5
def f4(x):
    return 0
def lucro(x):
    return (22250-45*x)/20

x = Symbol('x')
x1, =  solve(f1(x)-f2(x))
x2, =  solve(f1(x)-f3(x))
x3, =  solve(f2(x)-f3(x))
x4, =  solve(f3(x)-f4(x))
x5 = 0
x6 = 0

y1 = f1(x1)
y2 = f1(x2)
y3 = f2(x3)
y4 = f3(x4)
y5 = 0
y6 = 333.333

plt.figure(figsize=(10,10))

plt.plot(x1,f1(x1),'go',markersize=5)
plt.plot(x2,f1(x2),'go',markersize=5)
#plt.plot(x3,f2(x3),'go',markersize=5)
plt.plot(x4,f4(x4),'go',markersize=5)
plt.plot(x5,y5,'go',markersize=5)
plt.plot(x6,y6,'go',markersize=5)

plt.fill([x1,x2,x3,x4,x5,x6,x1],[y1,y2,y3,y4,y5,y6,y1],'pink',alpha=0.5)

xr = np.linspace(0.5,550,100)
y1r = f1(xr)
y2r = f2(xr)
y3r = f3(xr)
ylucror = lucro(xr)

plt.plot(xr,y1r,'k--', color='yellowgreen', label='tempo útil para produção')
plt.plot(xr,y2r,'k--', color='mediumslateblue', label='armazenamento')
plt.plot(xr,y3r,'k--', color='darkorange', label='matéria-prima')
plt.plot(xr,ylucror, color='k', label='lucro')

plt.xlim(0,500)
plt.ylim(0,550)

plt.legend()
plt.show()
# -

# ## c) Resolução pelo método simplex:

# # Tableau:

# +
index = ["Z", "S1", "S2", "S3"]
column_titles = ['Z','A','B','S1','S2','S3', 'Solução']
table_values = [[1,-45,-20,0,0,0,0],
                [0,1,1,1,0,0,550],
                [0,0.04,0.12,0,1,0,40],
                [0,20,5,0,0,1,9500]]

def table(index, table_values, column_titles):
    table = pd.DataFrame(table_values)
    table.index = [i for i in index]
    table.columns = [i for i in column_titles]
    return table

tableau = table(index, table_values, column_titles)
tableau
# -

matrix = np.array([[1,-45,-20,0,0,0,0],[0,1,1,1,0,0,550],[0,0.04,0.12,0,1,0,40],[0,20,5,0,0,1,9500]])
matrix = matrix.astype('float64')

# # TRANSFORMANDO ESSA MATRIZ EM MATRIZ IDENTIDADE POR <NAME>, É POSSIVEL DETERMINAR S1, S2 e S3 e depois, por fim, A e B.

#código para pivotar a matriz inteira
for i in range(1,4):
    for j in range(3):
        if i > j:
            if matrix[i][j] != 0:
                temp = matrix[i][j]/matrix[j][j]
                for k in range(4):
                    matrix[i][k] -= temp*matrix[j][k]

matrix = np.transpose(matrix)

#código para pivotar a matriz inteira
for i in range(1,4):
    for j in range(3):
        if i > j:
            if matrix[i][j] != 0:
                temp = matrix[i][j]/matrix[j][j]
                for k in range(4):
                    matrix[i][k] -= temp*matrix[j][k]

print(matrix)

matrix = np.transpose(matrix)

print(matrix)

# ## d) Resolução utilizando um pacote de software.

# ## Esta resolução está na planilha em anexo.

# ## e) 

# ## Analisando a resolução gráfica, é possível perceber que a restrição laranja sendo deslocada para a direita (isto é, seu coeficiente linear, ou seja, o valor do estoque de matéria prima), a reta preta também irá para a direita, ou seja, o lucro aumentará.
# ## SENDO ASSIM, a resposta procurada é aumentar o estoque de matéria-prima.

# # Análise

# ## As váriáveis de folga servem para avaliar quanto de um determinado recurso ainda está disponível. Se assumirem um valor negativo, a interpretação que se aplica é que está faltando aquele determinado recurso para a execução da tarefa. Valores positivos representam a sobra, e, por fim, quando a variável assume o valor zero, toda a quantidade em estoque foi consumida.

StarcoderdataJupyterScriptsDedupFiltered