yonicav/modeloptimiz
0
1# STREAMLIT2import streamlit as st3# DASHBOARD4import plotly.express as px5import random6from wordcloud import WordCloud7 8# PANDAS9import pandas as pd10# PYOMO11import pyomo.environ as pyo12from pyomo.environ import *13from pyomo.opt import SolverFactory14# GOOGLE AUTH15from google.oauth2 import service_account16# GSPREAD17import gspread as gs18# CURRENCY19import locale20 21### CONFIGS:22locale.setlocale(locale.LC_ALL, 'pt_BR')23st.set_page_config(24 page_title="Prescritive Analytics / Análise de Sugestão",25 page_icon="random",26 layout="wide",27 initial_sidebar_state="expanded",28)29 30### ACESSO AS PLANILHAS DO GOOGLE: 31##GRACIAS![https://medium.com/pyladiesbh/gspread-trabalhando-com-o-google-sheets-f12e53ed1346]32 33def login():34 '''35 FAZ O LOGIN NO GOOGLE DOCS USANDO CREDENCIAIS GCP36 '''37 scopes = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']38 credentials = service_account.Credentials.from_service_account_info(st.secrets["gcp_service_account"])39 scoped_credentials = credentials.with_scopes(scopes)40 gc = gs.authorize(scoped_credentials)41 return gc42 43def df_to_spreadsheet(spreadsheets,aba, df):44 '''45 Carrega um Dataframe em uma planilha do GDocs46 spreadsheets = nome da planilha47 aba = Aba do excel48 df = Dataframe49 '''50 gc = login()51 spreadsheet = gc.open(spreadsheets)52 wks = spreadsheet.worksheet(aba)53 wks.clear()54 data_list = df.values.tolist()55 wks.insert_rows(data_list)56 #header = ["Maq","Prod","Cliente","QtdProduction","Days","VALIDAÇAO","Custo_por_Ton","Capacidade_Max_por_dia","Valor_Frete","QtdContainers","ValorDeliveryTotal","Valor Total de Produção SEM FRETE","Model OF"]57 wks.insert_row(df.columns.tolist(), 1)58 59def df_from_spreadsheet(spreadsheets,aba):60 '''61 Carrega um Dataframe de uma planilha do GDocs62 spreadsheets = nome da planilha63 aba = Aba do excel64 retorna: Dataframe previamente formatado65 '''66 gc = login()67 spreadsheet = gc.open(spreadsheets)68 wks = spreadsheet.worksheet(aba)69 data = wks.get_all_values()70 headers = data.pop(0)71 df = pd.DataFrame(data, columns=headers)72 df = df.set_index(aba)73 df.index.name = None74 df = df.apply(lambda x: x.str.replace(',','.'))75 for column in df.columns:76 df[column] = pd.to_numeric(df[column])77 return df78 79def roda_algoritmo(container, dias):80 '''81 roda o algoritmo de sugestao82 container = quantidade de itens no pacote(frete)83 dias = quantidade de dias para fabricacao da demanda84 '''85 ### CAPACIDADE86 df_capacidade = df_from_spreadsheet("pyomo","CAPACIDADE")87 df_capacidade = df_capacidade.fillna(1)88 ### CUSTO89 df_custo = df_from_spreadsheet("pyomo","CUSTO")90 df_custo = df_custo.fillna(10000000)91 ### DEMANDA92 df_demanda = df_from_spreadsheet("pyomo","DEMANDA")93 df_demanda = df_demanda.fillna(0)94 ### FRETE95 df_frete = df_from_spreadsheet("pyomo","FRETE")96 df_frete = df_frete.fillna(0)97 df_frete = df_frete.T98 99 ### ALGORITMO DE OTIMIZAÇÃO:100 model = ConcreteModel()101 model.i = df_custo.keys() ## i=Machines102 model.j = df_demanda.index ## j=Products103 model.h = df_demanda.keys() ## h=Customers104 105 model.x = Var(model.i, model.j,model.h, within=NonNegativeReals) ### Quantity106 model.y = Var(model.i, model.j,model.h, bounds=(0,dias), within=NonNegativeReals) ### Days107 model.OF = Var(within=Reals) ### Total production Cost108 model.P = Var(model.i,within=Reals) ### Production by Machin 109 def rule_C0(model, i):110 return sum(model.x[i,j,h] for j in model.j for h in model.h) == model.P[i]111 model.C0 = Constraint(model.i, rule=rule_C0)112 model.C1 = ConstraintList()113 for j in model.j:114 for h in model.h:115 if df_demanda.loc[j,h] > 0:116 model.C1.add(sum(model.x[i,j,h] for i in model.i) == (df_demanda.loc[j,h] ) )117 model.C2 = ConstraintList()118 for i in model.i:119 for j in model.j:120 for h in model.h:121 model.C2.add(model.x[i,j,h] == (df_capacidade.loc[j,i] * model.y[i,j,h]) )122 model.C01 = ConstraintList() # DIAS_TOTAL123 for i in model.i:124 model.C01.add(sum(model.y[i,j,h] for h in model.h for j in model.j) <= dias)125 126 def rule_OF(model): 127 return model.OF == sum(128 (model.x[i,j,h] * df_custo.loc[j,i])129 +130 (131 (model.x[i,j,h] / container) 132 * 133 df_frete.loc[i,h]) for i in model.i for j in model.j for h in model.h)134 model.C3 = Constraint(rule=rule_OF)135 model.obj1 = Objective(expr=model.OF, sense=minimize)136 solver = SolverFactory('glpk')137 results = solver.solve(model, tee=True)138 print(results)139 print("RESULTADO:", results.solver.termination_condition)140 vOF = value(model.OF)141 #print("OF= ",vOF )142 columns1=('Maq','Prod', 'Cliente', 'QtdProduction', 'Days',"VALIDAÇAO","Custo_por_Ton", "Capacidade_Max_por_dia", "Valor_Frete", "QtdContainers", "ValorDeliveryTotal", "Valor Total de Produção SEM FRETE", 'Model OF')143 df = pd.DataFrame(columns = columns1)144 for i in model.i:145 for j in model.j:146 for h in model.h:147 v1 = value(model.x[i,j,h])148 v2 = value(model.y[i,j,h]) 149 v3 = value(df_custo.loc[j,i])150 v4 = value(df_capacidade.loc[j,i])151 v41 = value(df_frete.loc[i,h])152 v5 = ( v1 / container) 153 v6 = ( v1 / container) * df_frete.loc[i,h]154 v7 = (v1 * v3)155 v8 = (v1 * v3) + v6 156 if v1>0:157 #model.x[i,j,h] * custo[i][j]158 #print (i, j, h, v1, v2, v3,v4)159 df = df.append(pd.DataFrame({"Maq":[i], "Prod":[j], "Cliente":[h], "QtdProduction":[v1], "Days":[v2], "Custo_por_Ton": v3,160 "Capacidade_Max_por_dia": v4,"Valor_Frete": v41, "QtdContainers" : v5, "ValorDeliveryTotal" : v6, "Valor Total de Produção SEM FRETE": v7, "Model OF": v8}))161 return(df,vOF)162 163 164 165#### UX:166def main():167 st.title("Prescritive Analytics / Análise de Sugestão / Pesquisa Operacional")168 menu = ["HOME", "I - Linha de Produção Simples", "II - Linha de Produção Elaborada", "III - Carteira de Investimentos", "SOBRE"]169 choice = st.sidebar.selectbox("Menu", menu)170 171 172#### HOME:173 if choice == "HOME":174 st.markdown('''175 O objetivo é demonstrar de forma prática os conceitos em torno das soluções que utilizam ferramentas de uma área da 176 **Inteligência Artificial** chamada de **Análise de Sugestão**, utilizada para tomada de decisão onde existen grandes quantidade de opções.177 ''')178 with st.expander("Conceitos:"):179 st.markdown(180 '''181 A **Análise de Sugestão/Recomendação/Prescritiva** é utilizada para obtenção da melhor solução de todas as soluções viáveis 182 a fim de atingir um objetivo levando em consideração algumas restrições. Um problema de otimização consiste em *maximizar* 183 ou *minimizar* uma função objetivo, e encontrar a melhor solução de todas as soluções viáveis.184 185 A tecnologia de **Análise Prescritiva** recomenda ações com base nos resultados desejados, levando em consideração cenários 186 específicos, recursos e conhecimento de eventos passados e atuais. Esses insights podem ajudar sua organização à tomar 187 melhores decisões e ter maior controle dos resultados os negócios. A **Análise Prescritiva** fornece às organizações 188 recomendações sobre as ações ideais para atingir os objetivos de negócios, como satisfação do cliente, lucros e economia 189 de custos.190 191 As soluções de **Análise Prescritiva** usam tecnologia de otimização para resolver decisões complexas com milhões de variáveis 192 de decisão, restrições e regulagens. Organizações em dos os setores usam análises prescritivas para uma variedade de casos193 de uso que abrangem o planejamento estratégico, atividades operacionais e táticas. A **Análise Prescritiva** é a próxima etapa 194 no caminho para ações baseadas em insights. Ele cria valor por meio da sinergia com a **Análise PREDITIVA**, que analisa os 195 dados do passado para prever resultados futuros. A **Análise Prescritiva** leva esse insight para o próximo nível, sugerindo a 196 maneira ideal de lidar com essa situação futura. Organizações que podem agir rapidamente em condições dinâmicas e tomar decisões 197 superiores em ambientes incertos ganham uma forte vantagem competitiva. 198 ''' )199 200 st.markdown("No Menu tem os seguintes exemplos:")201 st.markdown(" Linha de Produção Simples: \n Objetivo: Exemplo simples de uma padaria para demostrar o potencial de soluções que utilizam PO para tomada de decisão")202 st.markdown(" Linha de Produção Elaborada: \n Objetivo: Exemplo mais complexo, para Minimizar o custo de produção de vários produtos.")203 st.markdown(" Carteira de Investimentos: \n Objetivo: Demonstrar o potencial de soluções que utilizam PO para tomada de decisão sugerindo ações para montar carteira de investimentos.")204 205 # WORDCLOUD206 # FUNCAO PARA DEFINICAO DA COR:207 def grey_color_func(word, font_size, position, orientation, random_state=None,**kwargs):208 return "hsl(0, 0%%, %d%%)" % random.randint(30, 100)209 text = '"Pesquisa Operacional","Engenharia de Produção","Simulação Estocástica","Otimização Combinatória","Optimization","Prescriptive Analytics","Operations Research","Mathematical Optimization for Business Problems"'210 # CRIA A IMAGEM COMO WORDCLOUD211 wordcloud = WordCloud(background_color='black', max_font_size = 40,collocations=False).generate(text)212 #change the color setting213 wordcloud.recolor(color_func = grey_color_func)214 # plot215 fig = px.imshow(wordcloud)216 fig.update_layout(coloraxis_showscale=False)217 fig.update_layout(width=1300, height=800)218 fig.update_xaxes(showticklabels=False)219 fig.update_yaxes(showticklabels=False)220 st.plotly_chart(fig) 221 222 223#### MIX DE PRODUÇÃO - SIMPLES:224 if choice == "I - Linha de Produção Simples":225 st.subheader("Produção de BOLOS e TORTAS em uma Padaria")226 st.write('''227 Quantos Bolos e Tortas devem ser feitos para maximizar o lucro desses dois produtos sob determinadas condições?228 ''')229 image = "https://bimbon-assets.s3.amazonaws.com/ckeditor/picture/data/52701fe1f369336f5300063f/content_Przystanek_bimbon03.jpg"230 st.image(image, width=370,)231 with st.expander("Regras de Negócio:"):232 st.markdown(233 '''234 Uma padaria faz bolos e tortas todos os periodos. Há: 1 forno, 2 padeiros, 1 empacotador que trabalha apenas 22 periodos. 235 O bolo requer o uso do forno por 1 periodo e a torta requer 0,5 periodo. Cada padeiro precisa trabalhar para o bolo 0,5 pariodos e para torta 2 periodos. 236 O empacotador precisa trabalhar para o bolo 1 periodo e a torta 0,5 periodo. O lucro em cada bolo é R$ 15,00 e o lucro em cada torta é R$ 12,00. 237 238 Exemplo de valores:239 - 1 FORNO240 - 2 PADEIRO241 - 1 EMPACOTADOR que trabala 22 periodos.242 Tempo de Preparo: 243 - FORNO = BOLO 1 periodo + TORTA 0.5 periodo <=30 periodos244 - PADEIRO = BOLO 0.5 periodo + TORTA 2.0 periodo <=60 periodos ( 2 padeiros)245 - EMPACOTAOR = BOLO 1.O periodo + TORTA 0.5 periodo <=22 periodos246 - LUCRO BOLO = 15247 - LUCRO TORTA = 12248 Objetivo: Maximizar os Lucros com os dois produtos na linha de produção249 ''')250 251 with st.expander("Quantidade de produtos já vendidas dos produtos:"):252 253 col1, col2,col3 = st.columns(3)254 with col1:255 minBOLO = st.number_input('BOLO - Qtd min :', help='Fabricação mimima de Bolo - já demandada' , value=0)256 with col2:257 minTORTA = st.number_input('TORTA - Qtd min:', help='Fabricação mimima de Bolo - já demandada' , value=0) 258 with st.expander("Valor de lucro dos produtos:"):259 st.write("LUCRO:")260 col1, col2,col3 = st.columns(3)261 with col1:262 LucroBOLO = st.number_input('BOLO - Margem de Lucro:', help='Margem de Lucro do Bolo' , value=15.00, format="%.2f")263 with col2:264 LucroTORTA = st.number_input('TORTA - Margem de Lucro:', help='Margem de Lucro do Torta' , value=12.00, format="%.2f")265 with st.expander("Restrições/Condições que precisam ser respeitadas:"):266 st.write("Capacidade - BOLO:")267 col1, col2, col3 = st.columns(3)268 with col1:269 pFORNO = st.number_input('FORNO - Capacidade:', help='Capacidade máxima de tempo do FORNO em periodos' , value=30)270 with col2:271 pPADEIRO = st.number_input('PADEIRO - Capacidade:', help='Capacidade máxima de tempo do PADEIRO em periodos:', value=60)272 with col3:273 pEMPACOTADOR = st.number_input('EMPACOTADOR - Capacidade:', help='Capacidade máxima de tempo do EMPACOTADOR em periodos:', value=22)274 275 st.write("Tempo de preparo - BOLO:")276 col1, col2, col3 = st.columns(3)277 with col1:278 tFORNOBOLO = st.number_input('BOLO/FORNO - Tempo:', help='Tempo de preparo em periodos' , value=1.00, format="%.2f")279 with col2:280 tPADEIROBOLO = st.number_input('BOLO/PADEIRO - Tempo:', help='Tempo de preparo em periodos:', value=0.50, format="%.2f")281 with col3:282 tEMPACOTADORBOLO = st.number_input('BOLO/EMPACOTADOR - Tempo:', help='Tempo de preparo em periodos:', value=1.00, format="%.2f")283 284 st.write("Tempo de preparo - TORTA:")285 col1, col2, col3 = st.columns(3)286 with col1:287 tFORNOTORTA = st.number_input('TORTA/FORNO - Tempo:', help='Tempo de preparo em periodos' , value=0.50, format="%.2f")288 with col2:289 tPADEIROTORTA = st.number_input('TORTA/PADEIRO - Tempo:', help='Tempo de preparo em periodos:', value=2.00, format="%.2f")290 with col3:291 tEMPACOTADORTORTA = st.number_input('TORTA/EMPACOTADOR - Tempo:', help='Tempo de preparo em periodos:', value=0.50, format="%.2f")292 293 294 if st.button("Enviar"):295 model = ConcreteModel()296 ##### dual297 model.dual = Suffix(direction=Suffix.IMPORT)298 299 ## VARIAVEIS DE DECISAO: ---------------------------------300 BOLO = model.BOLO = pyo.Var(within=PositiveReals)301 TORTA = model.TORTA = pyo.Var(within=PositiveReals)302 303 ## CONSTRAINTS: ---------------------------------304 model.FORNO = pyo.Constraint(expr= tFORNOBOLO * BOLO + tFORNOTORTA * TORTA <= pFORNO)305 model.PADEIRO = pyo.Constraint(expr= tPADEIROBOLO * BOLO + tPADEIROTORTA * TORTA <= pPADEIRO)306 model.EMPACOTADOR = pyo.Constraint(expr= tEMPACOTADORBOLO *BOLO + tEMPACOTADORTORTA * TORTA <= pEMPACOTADOR)307 model.minBOLO = pyo.Constraint(expr= BOLO >= minBOLO)308 model.minTORTA = pyo.Constraint(expr= TORTA >= minTORTA)309 310 model.obj = pyo.Objective(expr= LucroBOLO*BOLO +LucroTORTA*TORTA, sense=maximize)311 model.pprint()312 313 solver = SolverFactory('glpk')314 results = solver.solve(model, tee=True)315 st.write("A solução encontrada é: ", results.solver.termination_condition)316 with st.expander(" DUAL:"):317 st.write("Capacidade semelhantes que daram o mesmo resulado:")318 for c in [model.FORNO, model.PADEIRO, model.EMPACOTADOR]:319 st.write(c, c(), c.lslack(), c.uslack(), model.dual[c])320 321 # print(results)322 st.write("Para obter o maior lucro a sugestão de fábricação é:")323 st.write("BOLO:",pyo.value(BOLO),"TORTA é:",pyo.value(TORTA) )324 st.write("LUCRO esperado será:", pyo.value(model.obj))325 with st.expander("Explicação:"):326 st.write( '(', LucroBOLO,' X ', pyo.value(BOLO) , ") + (" , LucroTORTA,' X ',pyo.value(TORTA) ,' = ', pyo.value(model.obj),')')327 328 329#### MIX DE PRODUÇÃO - ELABORADO:330 elif choice == "II - Linha de Produção Elaborada":331 st.subheader("Linha de Produção Elaborada") 332 with st.expander("Objetivo:"):333 st.markdown("Minimizar o custo de produção incluindo o valor do frete, que é um valor fixo por capacidade maxima por pacote. \n \n \334- Quantidade de produção x Custo de produção + Valor do Frete por embalagem. \n \335- A demanda precisa ser igual a quantidade que deverá ser produzida \n \336- A capacidade de produção diária precisa ser respeitada")337 st.write("Resultado: É quantidade de dias necessária, bem como a melhor alocação das máquinas, para minimizar o custo de produção da demanda" )338 339 st.write("Preencha os valores na planilha conforme abaixo:")340 col1, col2, col3 = st.columns(3)341 with col1:342 st.write("**CAPACIDADE**: Produção em cada Máquina em 1 periodo de tempo")343 st.write("**CUSTO**: Produção em cada uma Máquina em 1 periodo de tempo")344 with col2: 345 st.write("**DEMANDA**: Demanda de produtos pelos Clientes")346 st.write("**FRETE**: Valor para envio da Quantidade do Produto A pela Máquina X")347 348 col1, col2, col3 = st.columns(3)349 with col1:350 st_dias = st.number_input('Periodo:', help='Periodo para atingir a demanda. Em dias, por exemplo' , value=30)351 with col2:352 st_containers = st.number_input('Itens por pacote(frete):', help='Quantidade maxima de itens por pacote(frete):',value=2.50, format="%.2f")353 354 # embed streamlit docs in a streamlit app355 import streamlit.components.v1 as components356 components.iframe(st.secrets["private_gsheets_url"],width=1500, height=800)357 358 if st.button("Enviar"):359 with st.spinner('Processando...'):360 ## cria o dataframe com o resultado da sugestao:361 df,vOF = roda_algoritmo(st_containers, st_dias)362 st.success('Feito!')363 364 st.write("Custo total para fabricação da Demanda - aba Resultado:", locale.currency(vOF,grouping=True))365 st.dataframe(df)366 df.fillna('', inplace=True)367 df_to_spreadsheet("pyomo","RESULTADO",df)368 369 #### GRÁFICOS:370 fig = px.bar(df.groupby(['Maq']).agg({'Days': 'sum'}))371 fig.update_layout(title = "Utilização das Maquinas",width=1500, height=800)372 st.plotly_chart(fig)373 fig = px.bar(df, x='Maq', y='QtdProduction', color='Cliente', barmode ='stack')374 fig.update_layout(title = "Qtd de Produção por Máquina",width=1500, height=800)375 st.plotly_chart(fig)376 fig = px.bar(df, x='Maq', y='Days', color='Cliente', barmode ='stack')377 fig.update_layout(title = "Tempo de Producão por Cliente",width=1500, height=800)378 st.plotly_chart(fig)379 fig = px.bar(df, x='Maq', y='Days', color='Prod', barmode ='stack')380 fig.update_layout(title = "Tempo de Producão por Produto",width=1500, height=800)381 st.plotly_chart(fig) 382 383 384 385#### CARTEIRA DE INVESTIMENTOS: 386 elif choice == "III - Carteira de Investimentos":387 st.subheader("Carteira de Investimentos... em contrução.") 388 389 390 391 392 393 394#### SOBRE: 395 elif choice == "SOBRE":396 col1, col2, col3, col4= st.columns(4)397 with col1:398 with st.expander("Fonte"):399 st.write(400 """401 Livros: 402 - Pyomo Documentation - Release 5.7.1.dev0 - Aug 17, 2020 403 - Pesquisa Operacional para Cursos de Engenharia - Patrícia Belfiore & Luiz Paulo Fávero 404 - ...405 """ )406 407 st.info("Desenvolvido por Paulo Cristiano Klein, com ajuda de muitos amigos!\n"408 "Mantido por [Paulo Klein](https://www.linkedin.com/in/pauloklein/). "409 "Me visite também em https://github.com/Tianoklein")410 if st.button("OBRIGADO!!!"):411 st.balloons()412 html_temp = '''<a href="mailto:tianoklein@hotmail.com?subject=Streamlit DO/PO Parse&body=Tenho uma sugestão: "> Duvidas, criticas e sugestões </a>'''413 import streamlit.components.v1 as components414 components.html(html_temp)415 416 417if __name__ == '__main__':418 main()