def D_parameters(dataset, D):
    """
    Computes all 30 GA makespan solutions for each one 
    of the different threshold parameter values in D.
        
    :returns: pd.dataframe (makespans), dictionary (exeqution times)
    """
    # Create df to store makespan values
    df = pd.DataFrame(columns=D)
    # Initialize dictionary to store execution times
    times = {}
    for d in D:  # iterate over D values
        mk, time = solve_GA(dataset, D=d)
        df.loc[:, d] = mk  # Store makespans on new df column
        times[d] = round(time, 3)  # Round and store execution time

    return df, times
def Pminit_parameters(dataset, Pminit):
    """
    Computes all 30 GA makespan solutions for each one 
    of the different initial mutation probability values in Pminit.
        
    :returns: pd.dataframe(makespans), dictionary (exeqution times)
    """
    # Create df to store makespan values
    df = pd.DataFrame(columns=Pminit)
    # Initialize dictionary to store execution times
    times = {}
    for pminit in Pminit:  # iterate over Pminit values
        mk, time = solve_GA(dataset, Pminit=pminit)
        df.loc[:, pminit] = mk  # Store makespans on new df column
        times[pminit] = round(time, 3)  # Round and store execution time

    return df, times
def Pc_parameters(dataset, Pc):
    """
    Computes all 30 GA makespan solutions for each one 
    of the different crossover probability values in Pc.
    
    :returns: pd.dataframe (makespans), dictionary (exeqution times)
    """
    # Create df to store makespan values
    df = pd.DataFrame(columns=Pc)
    # Initialize dictionary to store execution times
    times = {}
    for pc in Pc:  # iterate over Pc values
        mk, time = solve_GA(dataset, Pc=pc)
        df.loc[:, pc] = mk  # Store makespans on new df column
        times[pc] = round(time, 3)  # Round and store execution time

    return df, times
def M_parameters(dataset, M):
    """
    This function takes as input a dataset with
    job times on every machine and returns a 
    dataframe with all 30 GA makespan solutions 
    for each one of the different population 
    sizes, along with average times.
    
    :returns: pd.dataframe (makespans), dictionary (exeqution times)
    """
    # Create df to store makespan values for different
    df = pd.DataFrame(columns=M)
    # Initialize dictionary to store execution times
    times = {}
    for m in M:  # iterate over population sizes
        mk, time = solve_GA(dataset, M=m)
        df.loc[:, m] = mk  # Store makespans on new df column
        times[m] = round(time, 3)  # Round and store execution time

    return df, times
    ax3.set_ylabel(ylabel, fontfamily='serif')

    # Make it more beautiful and save
    plt.tight_layout(rect=[0, 0.03, 1, 0.92])
    plt.savefig(car + '_all_parameters.pdf', facecolor=fig.get_facecolor())

# Use function to plot the effect
create4subplots(m_car6, pc_car6, pminit_car6, d_car6, titles[1], xlabels)

# After analyzing the plots, we obtain some optimal parameter values
# and we repeat GA on reC19 using these values
GA_reC19 = pd.DataFrame()
GA_reC19.loc[:, 'Default parameters'] = GA_df.loc[:, 'reC19']
GA_reC19.loc[:, 'Optimal parameters'], _ = solve_GA(reC19,
                                                    M=50,
                                                    Pc=0.9,
                                                    Pminit=0.6,
                                                    D=0.4)

# Visualize the default vs the optimal parameters
fig = plt.figure(facecolor='#FCF4DC')
red_square = dict(markerfacecolor='r', marker='s', markersize=4)
GA_reC19.plot(kind='box',
              patch_artist=True,
              flierprops=red_square,
              medianprops={
                  'linestyle': '-',
                  'linewidth': 5
              },
              showmeans=True,
              color={'medians': 'red'})