from gurobipy import *
from scenarioTree.scenarioTree_standard import ScenarioTree
from scenarioTree.scenarioTreeSobol import ScenarioTree_Sobol
import numpy as np
import random
from functions import *
from solvers import CLSP_S
from solvers import CLSP_FR
from instances import Instance
import shelve
import pandas as pd


#VARIABILI FISSE PER ORA
num_items=5
num_repl=5
horizon=50

random.seed(100)

#ESTRAZIONE VETTORE MEDIE E MATRICE VARIANZA COVARIANZA
    
mean=np.ndarray(shape=(1,num_items),dtype=int)
    
for i in range(num_items):
    mean[0,i]=random.randint(10,100)

var_coeff=[]
var=[]

for i in range(num_items):
    var_coeff.append(random.uniform(0.1,0.5))
    var.append(pow(mean[0,i]*var_coeff[i],2))
    
cov=create_cov(var)

#DOMANDE OUT OF SAMPLE(SALVATE IN UN FILE)

d=shelve.open('dataframes/matrice.dat')

D=d['FixedDemands']

d.close()

#CREAZIONE DATAFRAME VUOTO

df=pd.DataFrame(columns=["Seed parameters","Solver type","Seed tree","Tree type","Branching factors","Path number","Time period","Y0","Y1","Y2","Y3","Y4","S0","S1","S2","S3","S4","I0","I1","I2","I3","I4","Z0","Z1","Z2","Z3","Z4","D0","D1","D2","D3","D4","Cost","CumCost","Time","CumTime","Time Limit","MIP Gap","h_cost","g_cost","f_cost"])

#POPOLAZIONE DATASET, CICLO FOR SUI DIVERSI SEED

for seedP in [100,200,300,400,500,600,700,800,900,1000]:

    #ESTRAZIONE PARAMETRI COL SEED DELL'ITERAZIONE

    random.seed(seedP)
    
    #MAGAZZINO INIZIALE
    initial_inventory=[]
    for i in range(num_items):
        initial_inventory.append(random.randint(0,2*mean[0,i]))

    print(initial_inventory)

    #COSTI DI MAGAZZINO

    h=[]
    for i in range(num_items):
        h.append(random.randint(1,10))

    #PENALITA' PER DOMANDA NON SODDISFATTA

    g=[]
    for i in range(num_items):
        g.append(random.randint(50,100))
    
    #COSTI DI SETUP

    f=[]
    for i in range(num_items):
        f.append(mean[0,i]*0.5*4*h[i])
    
    #PROCESSING TIMES

    proc_time=[]
    for i in range(num_items):
        proc_time.append(random.uniform(1,5))
    
    #DISPONIBILITA' MASSIMA DELLA RISORSA

    cap_factor=2
    R=np.inner(proc_time,mean[0,])*cap_factor

    #TEMPI DI SETUP

    setup_factor=0.5
    setup_times=[]

    for i in range(num_items):
        setup_times.append(R*setup_factor/num_items)

    #FOR PER SCEGLIERE IL SOLVER, NELLE SIMULAZIONI SEMPRE 
    #1 (SOLVER CON MATEURISTICA), 0 INVECE SAREBBE IL SOLVER
    #STANDARD
    for solverType in [1]:


        #FOR PER SCEGLIERE IL SEED DELL'ALBERO 
        #(NELLE SIMULAZIONI SEMPRE 1111)
        for seedT in [1111]:
            
            #FOR PER SCEGLIERE IL TIPO DELL'ALBERO DI SCENARI
            #0=ALBERO STANDARD
            #1=ALBERO CON SEQUENZE DI SOBOL
            for treeType in [0,1]:
                
                #FOR SUI FATTORI DI RAMIFICAZIONE
                for bf in range(5):
                
                    if bf==0:
                        branching_factors=[5,3,2]
                    elif bf==1:
                        branching_factors=[5,3,2,2]
                    elif bf==2:
                        branching_factors=[6,5,2]
                    elif bf==3:
                        branching_factors=[5,3,3,2,1]
                    elif bf==4:
                        branching_factors=[9,5,2,1]
                
                    time_periods=len(branching_factors)+1
                    
                    #GENERAZIONE ALBERO DI SCENARI
                    if treeType==0:
                        Tree1=ScenarioTree('Tree1',branching_factors,num_items,mean,mean,cov,seedT)
                    elif treeType==1:
                        Tree1=ScenarioTree_Sobol('Tree1',branching_factors,num_items,mean,mean,cov,seedT)
                    
                    N=Tree1.number_of_nodes()
                    
                    setting={
                        'h':h,
                        'g':g,
                        'f':f,
                        'proc_time':proc_time,
                        'R':R,
                        'setup_times':setup_times,
                        'num_items':num_items,
                        'time_periods':time_periods,
                        'N':N
                    }

                    #CREAZIONE ISTANZA DEL PROBLEMA                   
                    instance1=Instance(setting)

                    #DEFINIZIONE DEL SOLVER
                    if solverType==0:
                        solver=CLSP_S(**setting)
                
                    elif solverType==1:
                        solver=CLSP_FR(**setting)
                
                    #FOR SUI 5 PERCORSI DI DOMANDA OUT OF SAMPLE
                    for path in range(5):
                    
                        cum_cost=0
                        cum_time=0
                    
                        I=[]
                        for l in range(num_items):
                            I.append(initial_inventory[l])
                        Z=np.zeros((num_items))

                        #FOR SUI 50 ISTANTI DI OGNI
                        #PERCORSO DI DOMANDA
                        for t in range(horizon):
                            time_limit=float('nan')
                            gap=0.0001
                            #DECISIONE DI PRODUZIONE Y USANDO IL SOLVER
                            [objV,Y,S,comp_time]=solver.solve(instance1, Tree1, I)
                            
                            #AGGIORNAMENTO MAGAZZINO
                            for k in range(num_items):
                                if I[k]+Y[k]-D[path,t,k]>0:
                                    I[k]=I[k]+Y[k]-D[path,t,k]
                                    Z[k]=0
                                else:
                                    Z[k]=-(I[k]+Y[k]-D[path,t,k])
                                    I[k]=0

                            #COSTO DI MAGAZZINO
                            h_cost=np.inner(I,h)
                            #COSTO PER LA DOMANDA NON SODDISFATTA
                            g_cost=np.inner(Z,g)
                            #COSTI DI SETUP
                            f_cost=np.inner(S,f)
                            #COSTO COMPLESSIVO ALL'ISTANTE t
                            cost=f_cost+h_cost+g_cost
                            #AGGIORNAMENTO COSTO E TEMPO COMPLESSIVO
                            cum_cost+=cost
                            cum_time+=comp_time
                            
                            #SALVATAGGIO NUOVA OSSERVAZIONE NEL DATAFRAME
                            new_obs={
                                "Seed parameters":[seedP],
                                "Solver type":[solverType],
                                "Seed tree":[seedT],
                                "Tree type":[treeType],
                                "Branching factors":[bf],
                                "Path number":[path],
                                "Time period":[t],
                                "Y0":[Y[0]],
                                "Y1":[Y[1]],
                                "Y2":[Y[2]],
                                "Y3":[Y[3]],
                                "Y4":[Y[4]],
                                "S0":[S[0]],
                                "S1":[S[1]],
                                "S2":[S[2]],
                                "S3":[S[3]],
                                "S4":[S[4]],
                                "I0":[I[0]],
                                "I1":[I[1]],
                                "I2":[I[2]],
                                "I3":[I[3]],
                                "I4":[I[4]],
                                "Z0":[Z[0]],
                                "Z1":[Z[1]],
                                "Z2":[Z[2]],
                                "Z3":[Z[3]],
                                "Z4":[Z[4]],
                                "D0":[D[path,t,0]],
                                "D1":[D[path,t,1]],
                                "D2":[D[path,t,2]],
                                "D3":[D[path,t,3]],
                                "D4":[D[path,t,4]],
                                "Cost":[cost],
                                "CumCost":[cum_cost],
                                "Time":[comp_time],
                                "CumTime":[cum_time],
                                "Time Limit":[time_limit],
                                "MIP Gap":[gap],
                                "h_cost":[h_cost],
                                "g_cost":[g_cost],
                                "f_cost":[f_cost]
                            }
                            
                            new=pd.DataFrame(new_obs)
                            df=pd.concat([df,new],ignore_index=True)
                        
df.to_csv("DatiSimulazioniRH15.csv",index=False)

