def mapping_opt_iterative_local_search(tg, ctg, ag, noc_rg, critical_rg, noncritical_rg, shm, iteration_num,
                                       sub_iteration, report, detailed_report, logging):
    if report:
        print("===========================================")
        print("STARTING MAPPING OPTIMIZATION...USING ITERATIVE LOCAL SEARCH...")

    best_tg = copy.deepcopy(tg)
    best_ag = copy.deepcopy(ag)
    best_ctg = copy.deepcopy(ctg)
    best_cost = Mapping_Functions.mapping_cost_function(tg, ag, shm, False)
    starting_cost = best_cost
    if report:
        print("INITIAL COST:"+str(starting_cost))
    mapping_cost_file = open('Generated_Files/Internal/LocalSearchMappingCost.txt', 'w')
    mapping_cost_file.close()
    mapping_process_file = open('Generated_Files/Internal/MappingProcess.txt', 'w')
    mapping_process_file.close()
    for Iteration in range(0, iteration_num):
        logging.info("        ITERATION:"+str(Iteration))
        random_seed = Config.mapping_random_seed
        random.seed(Config.mapping_random_seed)
        for i in range(0, Iteration):
            random_seed = random.randint(1, 100000)
        (current_tg, current_ctg, current_ag) = mapping_opt_local_search(tg, ctg, ag, noc_rg, critical_rg,
                                                                         noncritical_rg, shm, sub_iteration,
                                                                         False, detailed_report, logging,
                                                                         "LocalSearchMappingCost",
                                                                         "mapping_process_file_name", random_seed)
        if current_tg is not False:
            current_cost = Mapping_Functions.mapping_cost_function(current_tg, current_ag, shm, False)
            if current_cost <= best_cost:
                if current_cost < best_cost:
                    if report:
                        print("\033[32m* NOTE::\033[0mBETTER SOLUTION FOUND WITH COST: "+str(current_cost) +
                               "\t ITERATION: "+str(Iteration))
                    logging.info("NOTE:: MOVED TO SOLUTION WITH COST: "+str(current_cost)+"ITERATION: "+str(Iteration))
                else:
                    logging.info("NOTE:: MOVED TO SOLUTION WITH COST: "+str(current_cost)+"ITERATION: "+str(Iteration))
                best_tg = copy.deepcopy(current_tg)
                best_ag = copy.deepcopy(current_ag)
                best_ctg = copy.deepcopy(current_ctg)
                best_cost = current_cost
        del current_tg
        del current_ag
        del current_ctg
        Mapping_Functions.clear_mapping(tg, ctg, ag)
        counter = 0
        schedule = True
        random_seed = Config.mapping_random_seed
        random.seed(Config.mapping_random_seed)
        for i in range(0, Iteration):
            random_seed = random.randint(1, 100000)
        while not Mapping_Functions.make_initial_mapping(tg, ctg, ag, shm, noc_rg, critical_rg,
                                                         noncritical_rg, False, logging, random_seed):
            if counter == 10:   # we try 10 times to find some initial solution... how ever if it fails...
                schedule = False
                break
            counter += 1
        if schedule:
            Scheduling_Functions.clear_scheduling(ag)
            Scheduler.schedule_all(tg, ag, shm, False, logging)
        else:
            if report:
                print("\033[33mWARNING::\033[0m CAN NOT FIND ANOTHER FEASIBLE SOLUTION... ",
                       "ABORTING ITERATIVE LOCAL SEARCH...")
            logging.info("CAN NOT FIND ANOTHER FEASIBLE SOLUTION... ABORTING ITERATIVE LOCAL SEARCH...")
            if report:
                print("-------------------------------------")
                print("STARTING COST: "+str(starting_cost)+"\tFINAL COST: "+str(best_cost))
                print("IMPROVEMENT:"+str("{0:.2f}".format(100*(starting_cost-best_cost)/starting_cost))+" %")
            return best_tg, best_ctg, best_ag

    if report:
        print("-------------------------------------")
        print("STARTING COST:"+str(starting_cost)+"\tFINAL COST:"+str(best_cost))
        print("IMPROVEMENT:"+str("{0:.2f}".format(100*(starting_cost-best_cost)/starting_cost))+" %")
    return best_tg, best_ctg, best_ag
def mapping_opt_iterative_local_search(tg, ctg, ag, noc_rg, critical_rg, noncritical_rg, shm, iteration_num,
                                       sub_iteration, report, detailed_report, logging):
    if report:
        print ("===========================================")
        print ("STARTING MAPPING OPTIMIZATION...USING ITERATIVE LOCAL SEARCH...")

    best_tg = copy.deepcopy(tg)
    best_ag = copy.deepcopy(ag)
    best_ctg = copy.deepcopy(ctg)
    best_cost = Mapping_Functions.mapping_cost_function(tg, ag, shm, False)
    starting_cost = best_cost
    if report:
        print ("INITIAL COST:"+str(starting_cost))
    mapping_cost_file = open('Generated_Files/Internal/LocalSearchMappingCost.txt', 'w')
    mapping_cost_file.close()
    mapping_process_file = open('Generated_Files/Internal/MappingProcess.txt', 'w')
    mapping_process_file.close()
    for Iteration in range(0, iteration_num):
        logging.info("        ITERATION:"+str(Iteration))
        random_seed = Config.mapping_random_seed
        random.seed(Config.mapping_random_seed)
        for i in range(0, Iteration):
            random_seed = random.randint(1, 100000)
        (current_tg, current_ctg, current_ag) = mapping_opt_local_search(tg, ctg, ag, noc_rg, critical_rg,
                                                                         noncritical_rg, shm, sub_iteration,
                                                                         False, detailed_report, logging,
                                                                         "LocalSearchMappingCost",
                                                                         "mapping_process_file_name", random_seed)
        if current_tg is not False:
            current_cost = Mapping_Functions.mapping_cost_function(current_tg, current_ag, shm, False)
            if current_cost <= best_cost:
                if current_cost < best_cost:
                    if report:
                        print ("\033[32m* NOTE::\033[0mBETTER SOLUTION FOUND WITH COST: "+str(current_cost) +
                               "\t ITERATION: "+str(Iteration))
                    logging.info("NOTE:: MOVED TO SOLUTION WITH COST: "+str(current_cost)+"ITERATION: "+str(Iteration))
                else:
                    logging.info("NOTE:: MOVED TO SOLUTION WITH COST: "+str(current_cost)+"ITERATION: "+str(Iteration))
                best_tg = copy.deepcopy(current_tg)
                best_ag = copy.deepcopy(current_ag)
                best_ctg = copy.deepcopy(current_ctg)
                best_cost = current_cost
        del current_tg
        del current_ag
        del current_ctg
        Mapping_Functions.clear_mapping(tg, ctg, ag)
        counter = 0
        schedule = True
        random_seed = Config.mapping_random_seed
        random.seed(Config.mapping_random_seed)
        for i in range(0, Iteration):
            random_seed = random.randint(1, 100000)
        while not Mapping_Functions.make_initial_mapping(tg, ctg, ag, shm, noc_rg, critical_rg,
                                                         noncritical_rg, False, logging, random_seed):
            if counter == 10:   # we try 10 times to find some initial solution... how ever if it fails...
                schedule = False
                break
            counter += 1
        if schedule:
            Scheduling_Functions.clear_scheduling(ag)
            Scheduler.schedule_all(tg, ag, shm, False, logging)
        else:
            if report:
                print ("\033[33mWARNING::\033[0m CAN NOT FIND ANOTHER FEASIBLE SOLUTION... ",
                       "ABORTING ITERATIVE LOCAL SEARCH...")
            logging.info("CAN NOT FIND ANOTHER FEASIBLE SOLUTION... ABORTING ITERATIVE LOCAL SEARCH...")
            if report:
                print ("-------------------------------------")
                print ("STARTING COST: "+str(starting_cost)+"\tFINAL COST: "+str(best_cost))
                print ("IMPROVEMENT:"+str("{0:.2f}".format(100*(starting_cost-best_cost)/starting_cost))+" %")
            return best_tg, best_ctg, best_ag

    if report:
        print ("-------------------------------------")
        print ("STARTING COST:"+str(starting_cost)+"\tFINAL COST:"+str(best_cost))
        print ("IMPROVEMENT:"+str("{0:.2f}".format(100*(starting_cost-best_cost)/starting_cost))+" %")
    return best_tg, best_ctg, best_ag
def optimize_mapping_sa(tg, ctg, ag, noc_rg, critical_rg, noncritical_rg, shm,
                        cost_data_file, logging):
    print("===========================================")
    print("STARTING MAPPING OPTIMIZATION...USING SIMULATED ANNEALING...")
    print("STARTING TEMPERATURE: " + str(Config.SA_InitialTemp))
    print("ANNEALING SCHEDULE: " + Config.SA_AnnealingSchedule)
    print("TERMINATION CRITERIA: " + Config.TerminationCriteria)
    print("================")

    if type(cost_data_file) is str:
        mapping_cost_file = open(
            'Generated_Files/Internal/' + cost_data_file + '.txt', 'a')
    else:
        raise ValueError("cost_data_file name is not string: " +
                         str(cost_data_file))

    mapping_process_file = open('Generated_Files/Internal/MappingProcess.txt',
                                'w')
    sa_temperature_file = open('Generated_Files/Internal/SATemp.txt', 'w')
    sa_cost_slop_file = open('Generated_Files/Internal/SACostSlope.txt', 'w')
    sa_huang_race_file = open('Generated_Files/Internal/SAHuangRace.txt', 'w')

    if Config.SA_AnnealingSchedule in ['Adaptive', 'Aart', 'Huang']:
        cost_monitor = deque([])
    else:
        cost_monitor = []

    if Config.DistanceBetweenMapping:
        init_map_string = Mapping_Functions.mapping_into_string(tg)
        if Config.Mapping_CostFunctionType == 'CONSTANT':
            Mapping_Functions.clear_mapping(tg, ctg, ag)
            if not Mapping_Functions.make_initial_mapping(
                    tg, ctg, ag, shm, noc_rg, critical_rg, noncritical_rg,
                    True, logging, Config.mapping_random_seed):
                raise ValueError("FEASIBLE MAPPING NOT FOUND...")
    else:
        init_map_string = None

    current_tg = copy.deepcopy(tg)
    current_ag = copy.deepcopy(ag)
    current_ctg = copy.deepcopy(ctg)
    current_cost = Mapping_Functions.mapping_cost_function(
        tg, ag, shm, False, initial_mapping_string=init_map_string)
    starting_cost = current_cost

    best_tg = copy.deepcopy(tg)
    best_ag = copy.deepcopy(ag)
    best_ctg = copy.deepcopy(ctg)
    best_cost = current_cost

    initial_temp = Config.SA_InitialTemp
    sa_temperature_file.write(str(initial_temp) + "\n")
    temperature = initial_temp
    slope = None
    zero_slope_counter = 0
    standard_deviation = None

    # for Huang Annealing schedule
    huang_counter1 = 0
    huang_counter2 = 0
    huang_steady_counter = 0
    iteration_num = Config.SimulatedAnnealingIteration
    # for i in range(0, iteration_num):
    #       move to another solution
    i = 0
    while True:
        i += 1
        new_tg, new_ctg, new_ag = move_to_next_solution(
            i, current_tg, current_ctg, current_ag, noc_rg, shm, critical_rg,
            noncritical_rg, logging)
        Scheduling_Functions.clear_scheduling(new_ag)
        Scheduler.schedule_all(new_tg, new_ag, shm, False, logging)

        # calculate the cost of new solution
        new_cost = Mapping_Functions.mapping_cost_function(
            new_tg, new_ag, shm, False, initial_mapping_string=init_map_string)

        if new_cost < best_cost:
            best_tg = copy.deepcopy(new_tg)
            best_ag = copy.deepcopy(new_ag)
            best_ctg = copy.deepcopy(new_ctg)
            best_cost = new_cost
            print("\033[33m* NOTE::\033[0mFOUND BETTER SOLUTION WITH COST:" +
                  "{0:.2f}".format(new_cost) + "\t ITERATION:" + str(i) +
                  "\tIMPROVEMENT:" +
                  "{0:.2f}".format(100 * (starting_cost - new_cost) /
                                   starting_cost) + " %")
        # calculate the probability P of accepting the solution
        prob = metropolis(current_cost, new_cost, temperature)
        # print("prob:", prob)
        # throw the coin with probability P
        random_seed = Config.mapping_random_seed
        random.seed(Config.mapping_random_seed)
        for j in range(0, i):
            random_seed = random.randint(1, 100000)
        random.seed(random_seed)
        logging.info("Throwing Dice: random_seed: " + str(random_seed) +
                     "    iteration: " + str(i))
        if prob > random.random():
            # accept the new solution
            move_accepted = True
            current_tg = copy.deepcopy(new_tg)
            current_ag = copy.deepcopy(new_ag)
            current_ctg = copy.deepcopy(new_ctg)
            current_cost = new_cost
            if Config.SA_ReportSolutions:
                if slope is not None:
                    print(
                        "\033[32m* NOTE::\033[0mMOVED TO SOLUTION WITH COST:",
                        "{0:.2f}".format(current_cost), "\tprob:",
                        "{0:.2f}".format(prob), "\tTemp:",
                        "{0:.2f}".format(temperature), "\t Iteration:", i,
                        "\tSLOPE:", "{0:.2f}".format(slope))
                if standard_deviation is not None:
                    print(
                        "\033[32m* NOTE::\033[0mMOVED TO SOLUTION WITH COST:",
                        "{0:.2f}".format(current_cost), "\tprob:",
                        "{0:.2f}".format(prob), "\tTemp:",
                        "{0:.2f}".format(temperature), "\t Iteration:", i,
                        "\tSTD_DEV:", "{0:.2f}".format(standard_deviation))
                else:
                    print(
                        "\033[32m* NOTE::\033[0mMOVED TO SOLUTION WITH COST:",
                        "{0:.2f}".format(current_cost), "\tprob:",
                        "{0:.2f}".format(prob), "\tTemp:",
                        "{0:.2f}".format(temperature), "\t Iteration:", i)
        else:
            move_accepted = False
            # move back to initial solution
            pass
        # update Temp
        mapping_process_file.write(
            Mapping_Functions.mapping_into_string(current_tg) + "\n")
        sa_temperature_file.write(str(temperature) + "\n")
        mapping_cost_file.write(str(current_cost) + "\n")

        if Config.SA_AnnealingSchedule == 'Adaptive':
            if len(cost_monitor) > Config.CostMonitorQueSize:
                cost_monitor.appendleft(current_cost)
                cost_monitor.pop()
            else:
                cost_monitor.appendleft(current_cost)
            slope = calculate_slope_of_cost(cost_monitor)
            if slope == 0:
                zero_slope_counter += 1
            else:
                zero_slope_counter = 0
            sa_cost_slop_file.write(str(slope) + "\n")

        if Config.SA_AnnealingSchedule == 'Aart':
            if len(cost_monitor) == Config.CostMonitorQueSize:
                standard_deviation = statistics.stdev(cost_monitor)
                cost_monitor.clear()
                # print(standard_deviation)
            else:
                cost_monitor.appendleft(current_cost)

        # Huang's annealing schedule is very much like Aart's Schedule... how ever, Aart's schedule stays in a fixed
        # temperature for a fixed number of steps, however, Huang's schedule decides about number of steps dynamically

        if Config.SA_AnnealingSchedule == 'Huang':
            cost_monitor.appendleft(current_cost)
            if len(cost_monitor) > 1:
                huang_cost_mean = sum(cost_monitor) / len(cost_monitor)
                huang_cost_sd = statistics.stdev(cost_monitor)
                if move_accepted:
                    if huang_cost_mean - Config.HuangAlpha * huang_cost_sd <= current_cost <= \
                            huang_cost_mean + Config.HuangAlpha * huang_cost_sd:
                        huang_counter1 += 1
                    else:
                        huang_counter2 += 1
            # print(huang_counter1, huang_counter2)
            sa_huang_race_file.write(
                str(huang_counter1) + " " + str(huang_counter2) + "\n")
            if huang_counter1 == Config.HuangTargetValue1:
                standard_deviation = statistics.stdev(cost_monitor)
                cost_monitor.clear()
                huang_counter1 = 0
                huang_counter2 = 0
                huang_steady_counter = 0
            elif huang_counter2 == Config.HuangTargetValue2:
                huang_counter1 = 0
                huang_counter2 = 0
                standard_deviation = None
            elif huang_steady_counter == Config.CostMonitorQueSize:
                standard_deviation = statistics.stdev(cost_monitor)
                cost_monitor.clear()
                huang_counter1 = 0
                huang_counter2 = 0
                huang_steady_counter = 0
                print(
                    "\033[36m* COOLING::\033[0m REACHED MAX STEADY STATE... PREPARING FOR COOLING..."
                )
            else:
                standard_deviation = None

            huang_steady_counter += 1

        temperature = next_temp(initial_temp, i, iteration_num, temperature,
                                slope, standard_deviation)

        if Config.SA_AnnealingSchedule == 'Adaptive':
            if zero_slope_counter == Config.MaxSteadyState:
                print("NO IMPROVEMENT POSSIBLE...")
                break
        if Config.TerminationCriteria == 'IterationNum':
            if i == Config.SimulatedAnnealingIteration:
                print("REACHED MAXIMUM ITERATION NUMBER...")
                break
        elif Config.TerminationCriteria == 'StopTemp':
            if temperature <= Config.SA_StopTemp:
                print("REACHED STOP TEMPERATURE...")
                break

    mapping_cost_file.close()
    mapping_process_file.close()
    sa_temperature_file.close()
    sa_cost_slop_file.close()
    sa_huang_race_file.close()
    print("-------------------------------------")
    print("STARTING COST:" + str(starting_cost) + "\tFINAL COST:" +
          str(best_cost))
    print("IMPROVEMENT:" +
          "{0:.2f}".format(100 *
                           (starting_cost - best_cost) / starting_cost) + " %")
    return best_tg, best_ctg, best_ag
def optimize_mapping_sa(tg, ctg, ag, noc_rg, critical_rg, noncritical_rg,
                        shm, cost_data_file, logging):
    print ("===========================================")
    print ("STARTING MAPPING OPTIMIZATION...USING SIMULATED ANNEALING...")
    print ("STARTING TEMPERATURE: "+str(Config.SA_InitialTemp))
    print ("ANNEALING SCHEDULE: "+Config.SA_AnnealingSchedule)
    print ("TERMINATION CRITERIA: "+Config.TerminationCriteria)
    print ("================")

    if type(cost_data_file) is str:
        mapping_cost_file = open('Generated_Files/Internal/'+cost_data_file+'.txt', 'a')
    else:
        raise ValueError("cost_data_file name is not string: "+str(cost_data_file))

    mapping_process_file = open('Generated_Files/Internal/MappingProcess.txt', 'w')
    sa_temperature_file = open('Generated_Files/Internal/SATemp.txt', 'w')
    sa_cost_slop_file = open('Generated_Files/Internal/SACostSlope.txt', 'w')
    sa_huang_race_file = open('Generated_Files/Internal/SAHuangRace.txt', 'w')

    if Config.SA_AnnealingSchedule in ['Adaptive', 'Aart', 'Huang']:
        cost_monitor = deque([])
    else:
        cost_monitor = []

    if Config.DistanceBetweenMapping:
        init_map_string = Mapping_Functions.mapping_into_string(tg)
        if Config.Mapping_CostFunctionType == 'CONSTANT':
            Mapping_Functions.clear_mapping(tg, ctg, ag)
            if not Mapping_Functions.make_initial_mapping(tg, ctg, ag, shm, noc_rg, critical_rg,
                                                          noncritical_rg, True, logging,
                                                          Config.mapping_random_seed):
                raise ValueError("FEASIBLE MAPPING NOT FOUND...")
    else:
        init_map_string = None

    current_tg = copy.deepcopy(tg)
    current_ag = copy.deepcopy(ag)
    current_ctg = copy.deepcopy(ctg)
    current_cost = Mapping_Functions.mapping_cost_function(tg, ag, shm, False, initial_mapping_string=init_map_string)
    starting_cost = current_cost

    best_tg = copy.deepcopy(tg)
    best_ag = copy.deepcopy(ag)
    best_ctg = copy.deepcopy(ctg)
    best_cost = current_cost

    initial_temp = Config.SA_InitialTemp
    sa_temperature_file.write(str(initial_temp)+"\n")
    temperature = initial_temp
    slope = None
    zero_slope_counter = 0
    standard_deviation = None

    # for Huang Annealing schedule
    huang_counter1 = 0
    huang_counter2 = 0
    huang_steady_counter = 0
    iteration_num = Config.SimulatedAnnealingIteration
    # for i in range(0, iteration_num):
    #       move to another solution
    i = 0
    while True:
        i += 1
        new_tg, new_ctg, new_ag = move_to_next_solution(i, current_tg, current_ctg, current_ag,  noc_rg,
                                                        shm, critical_rg, noncritical_rg, logging)
        Scheduling_Functions.clear_scheduling(new_ag)
        Scheduler.schedule_all(new_tg, new_ag, shm, False, logging)

        # calculate the cost of new solution
        new_cost = Mapping_Functions.mapping_cost_function(new_tg, new_ag, shm, False,
                                                           initial_mapping_string=init_map_string)

        if new_cost < best_cost:
            best_tg = copy.deepcopy(new_tg)
            best_ag = copy.deepcopy(new_ag)
            best_ctg = copy.deepcopy(new_ctg)
            best_cost = new_cost
            print ("\033[33m* NOTE::\033[0mFOUND BETTER SOLUTION WITH COST:"+"{0:.2f}".format(new_cost) +
                   "\t ITERATION:"+str(i)+"\tIMPROVEMENT:" +
                   "{0:.2f}".format(100*(starting_cost-new_cost)/starting_cost)+" %")
        # calculate the probability P of accepting the solution
        prob = metropolis(current_cost, new_cost, temperature)
        # print ("prob:", prob)
        # throw the coin with probability P
        random_seed = Config.mapping_random_seed
        random.seed(Config.mapping_random_seed)
        for j in range(0, i):
            random_seed = random.randint(1, 100000)
        random.seed(random_seed)
        logging.info("Throwing Dice: random_seed: "+str(random_seed)+"    iteration: "+str(i))
        if prob > random.random():
            # accept the new solution
            move_accepted = True
            current_tg = copy.deepcopy(new_tg)
            current_ag = copy.deepcopy(new_ag)
            current_ctg = copy.deepcopy(new_ctg)
            current_cost = new_cost
            if Config.SA_ReportSolutions:
                if slope is not None:
                    print ("\033[32m* NOTE::\033[0mMOVED TO SOLUTION WITH COST:", "{0:.2f}".format(current_cost),
                           "\tprob:", "{0:.2f}".format(prob), "\tTemp:", "{0:.2f}".format(temperature),
                           "\t Iteration:", i, "\tSLOPE:", "{0:.2f}".format(slope))
                if standard_deviation is not None:
                    print ("\033[32m* NOTE::\033[0mMOVED TO SOLUTION WITH COST:", "{0:.2f}".format(current_cost),
                           "\tprob:", "{0:.2f}".format(prob), "\tTemp:", "{0:.2f}".format(temperature),
                           "\t Iteration:", i, "\tSTD_DEV:", "{0:.2f}".format(standard_deviation))
                else:
                    print ("\033[32m* NOTE::\033[0mMOVED TO SOLUTION WITH COST:", "{0:.2f}".format(current_cost),
                           "\tprob:", "{0:.2f}".format(prob), "\tTemp:", "{0:.2f}".format(temperature),
                           "\t Iteration:", i)
        else:
            move_accepted = False
            # move back to initial solution
            pass
        # update Temp
        mapping_process_file.write(Mapping_Functions.mapping_into_string(current_tg)+"\n")
        sa_temperature_file.write(str(temperature)+"\n")
        mapping_cost_file.write(str(current_cost)+"\n")

        if Config.SA_AnnealingSchedule == 'Adaptive':
            if len(cost_monitor) > Config.CostMonitorQueSize:
                cost_monitor.appendleft(current_cost)
                cost_monitor.pop()
            else:
                cost_monitor.appendleft(current_cost)
            slope = calculate_slope_of_cost(cost_monitor)
            if slope == 0:
                zero_slope_counter += 1
            else:
                zero_slope_counter = 0
            sa_cost_slop_file.write(str(slope)+"\n")

        if Config.SA_AnnealingSchedule == 'Aart':
            if len(cost_monitor) == Config.CostMonitorQueSize:
                standard_deviation = statistics.stdev(cost_monitor)
                cost_monitor.clear()
                # print (standard_deviation)
            else:
                cost_monitor.appendleft(current_cost)

        # Huang's annealing schedule is very much like Aart's Schedule... how ever, Aart's schedule stays in a fixed
        # temperature for a fixed number of steps, however, Huang's schedule decides about number of steps dynamically

        if Config.SA_AnnealingSchedule == 'Huang':
            cost_monitor.appendleft(current_cost)
            if len(cost_monitor) > 1:
                huang_cost_mean = sum(cost_monitor)/len(cost_monitor)
                huang_cost_sd = statistics.stdev(cost_monitor)
                if move_accepted:
                    if huang_cost_mean - Config.HuangAlpha * huang_cost_sd <= current_cost <= \
                            huang_cost_mean + Config.HuangAlpha * huang_cost_sd:
                        huang_counter1 += 1
                    else:
                        huang_counter2 += 1
            # print (huang_counter1, huang_counter2)
            sa_huang_race_file.write(str(huang_counter1)+" "+str(huang_counter2)+"\n")
            if huang_counter1 == Config.HuangTargetValue1:
                standard_deviation = statistics.stdev(cost_monitor)
                cost_monitor.clear()
                huang_counter1 = 0
                huang_counter2 = 0
                huang_steady_counter = 0
            elif huang_counter2 == Config.HuangTargetValue2:
                huang_counter1 = 0
                huang_counter2 = 0
                standard_deviation = None
            elif huang_steady_counter == Config.CostMonitorQueSize:
                standard_deviation = statistics.stdev(cost_monitor)
                cost_monitor.clear()
                huang_counter1 = 0
                huang_counter2 = 0
                huang_steady_counter = 0
                print ("\033[36m* COOLING::\033[0m REACHED MAX STEADY STATE... PREPARING FOR COOLING...")
            else:
                standard_deviation = None

            huang_steady_counter += 1

        temperature = next_temp(initial_temp, i, iteration_num, temperature, slope, standard_deviation)

        if Config.SA_AnnealingSchedule == 'Adaptive':
            if zero_slope_counter == Config.MaxSteadyState:
                print ("NO IMPROVEMENT POSSIBLE...")
                break
        if Config.TerminationCriteria == 'IterationNum':
            if i == Config.SimulatedAnnealingIteration:
                print ("REACHED MAXIMUM ITERATION NUMBER...")
                break
        elif Config.TerminationCriteria == 'StopTemp':
            if temperature <= Config.SA_StopTemp:
                print ("REACHED STOP TEMPERATURE...")
                break

    mapping_cost_file.close()
    mapping_process_file.close()
    sa_temperature_file.close()
    sa_cost_slop_file.close()
    sa_huang_race_file.close()
    print ("-------------------------------------")
    print ("STARTING COST:"+str(starting_cost)+"\tFINAL COST:"+str(best_cost))
    print ("IMPROVEMENT:"+"{0:.2f}".format(100*(starting_cost-best_cost)/starting_cost)+" %")
    return best_tg, best_ctg, best_ag