def fitness(individual: IndividualType, indices: IndicesType, init_state: Dict, fleet: Fleet, hp: HyperParameters): """ Positive fitness of the individual. :param individual: the individual to evaluate :param fleet: fleet instance :param hp: GA hyper-parameters :return: fitness value of the individual (positive) """ # Decode routes = decode(individual, indices, init_state, fleet) # Set routes fleet.set_routes_of_vehicles(routes) # Cost costs = np.array(fleet.cost_function()) # Calculate penalization feasible, distance, accept = fleet.feasible() penalization = distance + hp.hard_penalization if fleet.deterministic else distance # Calculate fitness fit = np.dot(costs, np.asarray(hp.weights)) + penalization return fit, feasible, accept
def __init__(self, network_path: str, fleet_path: str, measurements_path: str, routes_path: str, history_path: str, mat_path: str, sample_time: float, main_folder: str = None, std_factor: Tuple = (1., 1.), create_routes_xml: bool = True, create_measurements_xml: bool = True, create_history_xml: bool = True): if main_folder: self.network_path = f'{main_folder}{network_path.split("/")[-1][:-4]}_temp.xml' self.fleet_path = f'{main_folder}{fleet_path.split("/")[-1][:-4]}_temp.xml' else: self.network_path = net_path self.fleet_path = fleet_path self.measurements_path = measurements_path self.history_path = history_path self.mat_path = mat_path self.sample_time = sample_time self.network = Network.from_xml(network_path, instance=False) self.fleet = Fleet.from_xml(fleet_path, assign_customers=False, with_routes=False, instance=False) self.network.write_xml(self.network_path, print_pretty=False) self.fleet.write_xml(self.fleet_path, network_in_file=False, assign_customers=False, with_routes=False, print_pretty=False) self.day_points = int(1440 / self.network.edges[0][0].sample_time) self.data = self.data_from_mat_file() if main_folder: self.routes_path = f'{main_folder}{routes_path.split("/")[-1]}' else: self.routes_path = routes_path self.routes, self.depart_info = Dispatcher.read_routes( routes_path, read_depart_info=True) Dispatcher.write_routes(self.routes_path, self.routes, self.depart_info, write_pretty=False) self.measurements, _ = self.create_measurements_file() self.history = FleetHistory().create_from_routes(self.routes) self.save_history() self.std_factor = std_factor
def fitness(individual: IndividualType, fleet: Fleet, hp: AlphaGA_HyperParameters): """ Positive fitness of the individual. :param individual: the individual to evaluate :param fleet: fleet instance :param hp: GA hyper-parameters :return: fitness value of the individual (positive) """ # Decode routes = decode(individual, fleet, hp) # Set routes fleet.set_routes_of_vehicles(routes) # Iterate fleet.iterate() # Cost costs = np.array(fleet.cost_function() ) # cost_tt, cost_ec, cost_chg_time, cost_chg_cost # Calculate penalization feasible, distance, accept = fleet.feasible() if distance > 0.: penalization = distance + hp.hard_penalization else: penalization = 0 # Calculate fitness fit = np.dot(costs, np.asarray(hp.weights)) + penalization return fit, feasible, accept
def fitness(individual: IndividualType, indices: IndicesType, critical_points: Dict, fleet: Fleet, hp: HyperParameters): """ Calculates fitness of individual. """ # Decode m = len(fleet.vehicles) routes = decode(individual, indices, critical_points, fleet, hp) # Set routes reaching_states = { id_ev: (r.x1_0, r.x2_0, r.x3_0) for id_ev, r in critical_points.items() } vehicles_pos = [cp.S0 for cp in critical_points.values()] init_theta = np.array( [1 if i in vehicles_pos else 0 for i in range(len(fleet.network))]) fleet.set_routes_of_vehicles(routes, reaching_states=reaching_states, init_theta=init_theta) # Cost costs = np.array(fleet.cost_function()) # Calculate penalization feasible, distance, accept = fleet.feasible() penalization = 0 if not accept: penalization = distance + hp.hard_penalization + hp.K2 elif accept and not feasible: penalization = distance + hp.hard_penalization # Calculate fitness fit = np.dot(costs, np.asarray(hp.weights)) + penalization return fit, feasible, accept
def alphaGA(fleet: Fleet, hp: AlphaGA_HyperParameters, save_to: str = None, init_pop=None, savefig=False, plot_best_generation=False): # OBJECTS creator.create("FitnessMin", base.Fitness, weights=(-1.0, )) creator.create("Individual", list, fitness=creator.FitnessMin, feasible=False, acceptable=False) # TOOLBOX toolbox = base.Toolbox() toolbox.register("individual", random_individual, num_customers=len(fleet.network.customers), num_cs=len(fleet.network.charging_stations), m=len(fleet), r=hp.r) toolbox.register("evaluate", fitness, fleet=fleet, hp=hp) toolbox.register("mate", crossover, fleet=fleet, hp=hp, block_probability=(.33, .33, .33), index=None) toolbox.register("mutate", mutate, fleet=fleet, hp=hp, block_probability=(.33, .33, .33), index=None) toolbox.register("select", tools.selTournament, tournsize=hp.tournament_size) toolbox.register("select_worst", tools.selWorst) toolbox.register("decode", decode, fleet=fleet, hp=hp) # BEGIN ALGORITHM t_init = time.time() # Population from first candidates random_inds_num = int(hp.num_individuals / 3) init_size = len(init_pop) mutate_num = hp.num_individuals - init_size - random_inds_num pop = [creator.Individual(i) for i in init_pop] # Random population pop += [ toolbox.mutate(toolbox.clone(pop[randint(0, init_size - 1)])) for i in range(mutate_num) ] pop += [ creator.Individual(toolbox.individual()) for _ in range(random_inds_num) ] # Evaluate the initial population and get fitness of each individual for k, ind in enumerate(pop): fit, feasible, acceptable = toolbox.evaluate(ind) ind.fitness.values = (fit, ) ind.feasible = feasible ind.acceptable = acceptable print(f' Evaluated {len(pop)} individuals') bestOfAll = tools.selBest(pop, 1)[0] print( f"Best individual : {bestOfAll}\n Fitness: {bestOfAll.fitness.wvalues[0]} Feasible: {bestOfAll.feasible}" ) # These will save statistics cs_capacity = fleet.network.nodes[ fleet.network.charging_stations[0]].capacity opt_data = GenerationsData([], [], [], [], [], [], fleet, hp, bestOfAll, bestOfAll.feasible, bestOfAll.acceptable, len(fleet), cs_capacity) print("################ Start of evolution ################") # Begin the evolution for g in range(hp.max_generations): # A new generation print(f"-- Generation {g}/{hp.max_generations} --") opt_data.generations.append(g) # Update block probabilities if g < 50: block_probabilities = (.33, .33, .33) elif g < 100: block_probabilities = (.2, .6, .2) elif g < 150: block_probabilities = (.6, .2, .2) elif g < 200: block_probabilities = (.33, .33, .33) elif g < 250: block_probabilities = (.2, .6, .2) elif g < 300: block_probabilities = (.6, .2, .33) else: block_probabilities = (.33, .33, .33) # Select the best individuals, if given if hp.elite_individuals: best_individuals = list( map(toolbox.clone, tools.selBest(pop, hp.elite_individuals))) # Select and clone the next generation individuals offspring = toolbox.select(pop, len(pop)) offspring = list(map(toolbox.clone, offspring)) # Mutation for mutant in offspring: if random() < hp.MUTPB: toolbox.mutate(mutant, block_probability=block_probabilities) del mutant.fitness.values # Crossover for child1, child2 in zip(offspring[::2], offspring[1::2]): if random() < hp.CXPB: toolbox.mate(child1, child2) del child1.fitness.values del child2.fitness.values # Evaluate the individuals with invalid fitness invalid_ind = [ind for ind in offspring if not ind.fitness.valid] for ind in invalid_ind: fit, feasible, acceptable = toolbox.evaluate(ind) ind.fitness.values = (fit, ) ind.feasible = feasible ind.acceptable = acceptable print(f' Evaluated {len(invalid_ind)} individuals') # The population is entirely replaced by a sorted offspring pop[:] = offspring pop[:] = tools.selBest(pop, len(pop)) # Insert best individuals from previous generation if hp.elite_individuals: pop[:] = best_individuals + pop[:-hp.elite_individuals] # Update best individual bestInd = tools.selBest(pop, 1)[0] if bestInd.fitness.wvalues[0] > bestOfAll.fitness.wvalues[0]: bestOfAll = bestInd # Real-time info print( f"Best individual : {bestInd}\n Fitness: {bestInd.fitness.wvalues[0]} Feasible: {bestInd.feasible} Acceptable: {bestInd.acceptable}" ) worstInd = tools.selWorst(pop, 1)[0] print( f"Worst individual : {worstInd}\n Fitness: {worstInd.fitness.wvalues[0]} Feasible: {worstInd.feasible} Acceptable: {worstInd.acceptable}" ) print( f"Curr. best-of-all: {bestOfAll}\n Fitness: {bestOfAll.fitness.wvalues[0]} Feasible: {bestOfAll.feasible} Acceptable: {bestOfAll.acceptable}" ) # Statistics fits = [sum(ind.fitness.wvalues) for ind in pop] mean = np.average(fits) std = np.std(fits) print(f"Max {max(fits)}") print(f"Min {min(fits)}") print(f"Avg {mean}") print(f"Std {std}") opt_data.best_fitness.append(-max(fits)) opt_data.worst_fitness.append(-min(fits)) opt_data.average_fitness.append(mean) opt_data.std_fitness.append(std) opt_data.best_individuals.append(bestInd) print() if plot_best_generation: toolbox.evaluate(bestOfAll) fleet.plot_operation_pyplot() plt.show() input('Press ENTER to evolve...') t_end = time.time() print("################ End of (successful) evolution ################") algo_time = t_end - t_init print('Algorithm time:', algo_time) fit, feasible, acceptable = toolbox.evaluate(bestOfAll) routes = toolbox.decode(bestOfAll) opt_data.bestOfAll = bestOfAll opt_data.feasible = feasible opt_data.acceptable = acceptable opt_data.algo_time = algo_time opt_data.fleet = fleet if save_to: path = save_to + hp.algorithm_name + f'_fleetsize_{len(fleet)}/' try: os.mkdir(path) except FileExistsError: pass opt_data.save_opt_data(path, savefig=savefig) return routes, opt_data, toolbox
max_payload = 0.58 # tonnes weight = 1.52 # tonnes max_tour_duration = 7 * 60. # %% Instance fleet if stochastic: ev = Fleet.EV.GaussianElectricVehicle(ev_id, weight, battery_capacity, battery_capacity_nominal, alpha_upp, alpha_down, max_tour_duration, max_payload) else: ev = Fleet.EV.ElectricVehicle(ev_id, weight, battery_capacity, battery_capacity_nominal, alpha_upp, alpha_down, max_tour_duration, max_payload) if stochastic: fleet = Fleet.GaussianFleet({0: ev}, network) else: fleet = Fleet.Fleet({0: ev}, network) fleet.hard_penalization = hard_penalization fleet.resize_fleet(fleet_size) # %% Save fleet fleet.write_xml(f'{main_folder}fleet.xml', network_in_file=True, assign_customers=False, with_routes=False, print_pretty=print_pretty) fleet2 = Fleet.from_xml(f'{main_folder}fleet.xml')
def betaGA(fleet: Fleet, hp: HyperParameters, save_to: str = None, best_ind: IndividualType = None, savefig=False): fleet.assign_customers_in_route() customers_to_visit = { ev_id: ev.assigned_customers for ev_id, ev in fleet.vehicles.items() } starting_points = { ev_id: (0, 0, fleet.vehicles[ev_id].state_leaving[0, 0], ev.alpha_up, sum([fleet.network.demand(x) for x in ev.assigned_customers])) for ev_id, ev in fleet.vehicles.items() } indices = block_indices(customers_to_visit) # Fitness objects creator.create("FitnessMin", base.Fitness, weights=(-1.0, )) creator.create("Individual", list, fitness=creator.FitnessMin, feasible=False, acceptable=False) # Toolbox toolbox = base.Toolbox() toolbox.register("individual", random_individual, customers_per_vehicle=customers_to_visit, charging_stations=fleet.network.charging_stations) toolbox.register("evaluate", fitness, indices=indices, init_state=starting_points, fleet=fleet, hp=hp) toolbox.register("mate", crossover, indices=indices, hp=hp) toolbox.register("mutate", mutate, indices=indices, charging_stations=fleet.network.charging_stations, hp=hp) toolbox.register("select", tools.selTournament, tournsize=hp.tournament_size) toolbox.register("select_worst", tools.selWorst) toolbox.register("decode", decode, indices=indices, init_state=starting_points, fleet=fleet) # BEGIN ALGORITHM t_init = time.time() # Random population if best_ind is not None: pop = [creator.Individual(best_ind)] else: pop = [] pop.append(creator.Individual(individual_from_routes(fleet))) pop = pop + [ creator.Individual(toolbox.individual()) for i in range(hp.num_individuals - len(pop)) ] # Evaluate the initial population and get fitness of each individual for ind in pop: fit, feasible, acceptable = toolbox.evaluate(ind) ind.fitness.values = (fit, ) ind.feasible = feasible ind.acceptable = acceptable print(f' Evaluated {len(pop)} individuals') bestOfAll = tools.selBest(pop, 1)[0] print( f"Best individual : {bestOfAll}\n Fitness: {bestOfAll.fitness.wvalues[0]} Feasible: {bestOfAll.feasible}" ) # These will save statistics m = len(fleet) cs_capacity = fleet.network.nodes[ fleet.network.charging_stations[0]].capacity opt_data = GenerationsData([], [], [], [], [], [], fleet, hp, bestOfAll, bestOfAll.feasible, bestOfAll.acceptable, m, cs_capacity) print("################ Start of evolution ################") # Begin the evolution for g in range(hp.max_generations): # A new generation print(f"-- Generation {g}/{hp.max_generations} --") opt_data.generations.append(g) # Update block probabilities if g < 50: block_probabilities = (.33, .33, .33) elif g < 100: block_probabilities = (.2, .6, .2) elif g < 150: block_probabilities = (.6, .2, .2) elif g < 200: block_probabilities = (.33, .33, .33) elif g < 250: block_probabilities = (.2, .6, .2) elif g < 300: block_probabilities = (.6, .2, .33) else: block_probabilities = (.33, .33, .33) # Select the best individuals, if given if hp.elite_individuals: best_individuals = list( map(toolbox.clone, tools.selBest(pop, hp.elite_individuals))) # Select and clone the next generation individuals offspring = toolbox.select(pop, len(pop)) offspring = list(map(toolbox.clone, offspring)) # Mutation for mutant in offspring: if random() < hp.MUTPB: toolbox.mutate(mutant) del mutant.fitness.values # Crossover for child1, child2 in zip(offspring[::2], offspring[1::2]): if random() < hp.CXPB: toolbox.mate(child1, child2) del child1.fitness.values del child2.fitness.values # Evaluate the individuals with invalid fitness invalid_ind = [ind for ind in offspring if not ind.fitness.valid] for ind in invalid_ind: fit, feasible, acceptable = toolbox.evaluate(ind) ind.fitness.values = (fit, ) ind.feasible = feasible ind.acceptable = acceptable print(f' Evaluated {len(invalid_ind)} individuals') # The population is entirely replaced by a sorted offspring pop[:] = offspring pop[:] = tools.selBest(pop, len(pop)) # Insert best individuals from previous generation if hp.elite_individuals: pop[:] = best_individuals + pop[:-hp.elite_individuals] # Update best individual bestInd = tools.selBest(pop, 1)[0] if bestInd.fitness.wvalues[0] > bestOfAll.fitness.wvalues[0]: bestOfAll = bestInd # Real-time info print( f"Best individual : {bestInd}\n Fitness: {bestInd.fitness.wvalues[0]} Feasible: {bestInd.feasible}" ) worstInd = tools.selWorst(pop, 1)[0] print( f"Worst individual : {worstInd}\n Fitness: {worstInd.fitness.wvalues[0]} Feasible: {worstInd.feasible}" ) print( f"Curr. best-of-all: {bestOfAll}\n Fitness: {bestOfAll.fitness.wvalues[0]} Feasible: {bestOfAll.feasible}" ) # Statistics fits = [sum(ind.fitness.wvalues) for ind in pop] mean = np.average(fits) std = np.std(fits) print(f"Max {max(fits)}") print(f"Min {min(fits)}") print(f"Avg {mean}") print(f"Std {std}") opt_data.best_fitness.append(-max(fits)) opt_data.worst_fitness.append(-min(fits)) opt_data.average_fitness.append(mean) opt_data.std_fitness.append(std) opt_data.best_individuals.append(bestInd) print() t_end = time.time() print("################ End of (successful) evolution ################") algo_time = t_end - t_init print('Algorithm time:', algo_time) fit, feasible, acceptable = toolbox.evaluate(bestOfAll) routes = toolbox.decode(bestOfAll) opt_data.bestOfAll = bestOfAll opt_data.feasible = feasible opt_data.acceptable = acceptable opt_data.algo_time = algo_time opt_data.fleet = fleet if save_to: path = save_to + hp.algorithm_name + f'_fleetsize_{m}/' try: os.mkdir(path) except FileExistsError: pass opt_data.save_opt_data(path, savefig=savefig) return routes, opt_data, toolbox
def update_fleet(self): self.fleet = Fleet.from_xml(self.fleet_path, assign_customers=False, with_routes=False, instance=False, from_online=False)
MUTPB=0.85, hard_penalization=200000, elite_individuals=1, tournament_size=5, r=3) hp_beta = GATools.BetaGA_HyperParameters(weights, CXPB=0.6, MUTPB=0.8, hard_penalization=200000, elite_individuals=1, tournament_size=5) if __name__ == '__main__': for i in range(3): # %% Read instance data fleet = Fleet.from_xml(folder + instance_name + '.xml') soc_policy = (fleet.vehicles[0].alpha_down, fleet.vehicles[0].alpha_up) # %% Initial population and fleet size N = int( sum([fleet.network.demand(i) for i in fleet.network.customers]) / fleet.vehicles[0].max_payload) + 1 fill_up_to = N / ( N + additional_vehicles) if additional_vehicles else fill_up_to init_pop, m = alphaGA.heuristic_population_1(hp_alpha.r, fleet, fill_up_to) fleet.resize_fleet(m) hp_alpha.num_individuals = 10 * len(fleet) + 5 * len( fleet.network) + 10 hp_alpha.max_generations = 3 * hp_alpha.num_individuals + 15 hp_alpha.alpha_up = fleet.vehicles[0].alpha_up