def _create_crossover(self, next_population_parents): crossovers = [] s_print("Adding crossovers --- STARTED") while len(crossovers) < self.population_limit * cross_over_ratio: crossovers.extend(crossover(next_population_parents)) s_print("Adding crossovers --- FINISHED") return crossovers
def create_mutation_thread(process_name, mutations, next_generation_parents): while True: mutation = mutate(next_generation_parents) if not (mutations.append(mutation)): break s_print("{} mutated with energy cost ${}".format( process_name, mutation.total_energy_cost()))
def _create_mutation(self, next_population_parents): mutations = [] s_print("Adding mutations --- STARTED") while len(mutations) < self.population_limit * mutation_ratio: mutations.append(mutate(next_population_parents)) s_print("Adding mutations --- FINISHED") return mutations
def mutate(next_population_parents): """ Args: next_population_parents: next generation parents Returns: mutated child assignment """ parent = random.choice(next_population_parents.copy()) mutation_count = max(min_mutation, int(mutation_prob * len(parent.get_trips()))) at_least_one_mutated = False start_time = datetime.now() parent_cpy = parent.copy() child = None while mutation_count > 0: if (datetime.now() - start_time).total_seconds() > mutation_break_time_limit: if not at_least_one_mutated: s_print("Nothing mutated breaking due to time limitation") break child, mutated = parent_cpy.mutate() if mutated: at_least_one_mutated = True mutation_count -= 1 parent_cpy = child.copy() else: parent_cpy = parent.copy() if child is None: child = parent.copy() return child.copy()
def assign(self, selected_trip, selected_bus): status = False if selected_trip not in self._trip_alloc: _info = self.add(selected_trip, selected_bus) if _info.feasible(): self._trip_alloc.append(selected_trip) self._update_stats(selected_bus) status = True else: if is_electric(selected_bus): if _info.time_feasible() and not _info.energy_feasible(): _res_info = self.assign_charge(_info, selected_bus, selected_trip) if _res_info.feasible(): _res_info_add = self.add(selected_trip, selected_bus) if _res_info_add.feasible(): self._trip_alloc.append(selected_trip) status = True else: if isinstance(selected_trip, OperatingTrip): if electric_bus_type.capacity < selected_trip.get_energy_consumed( electric_bus_type): s_print(_info.energy()) raise NotEnoughEVEnergyException( "EVBusEnergy is not enough for a single trip !!!" ) else: s_print(_info.energy()) raise NotEnoughEVEnergyException( "EVBusEnergy is not enough for a single trip !!!" ) return status
def print(self, info=""): print_hf(stat_header_length, info=info) super(BusStat, self).print() print_hf(movements_header_length, info="BUS MOVEMENTS") for time_in_seconds in sorted(self.movements.keys()): s_movement = self.movements[time_in_seconds] for movement in s_movement: s_print(movement.__str__())
def create_population_thread(process_name, populations, dump_structure, assign_util_config, arg): while True: assignment = assign(dump_structure, assign_util_config, arg) assign_type = assignment.get_type() if assignment is not None: if not (populations.append(assignment)): break s_print( "{} assigned with energy cost ${} using Algorithm {}".format( process_name, assignment.total_energy_cost(), str(assign_type)))
def create_crossover_thread(process_name, cross_overs, next_generation_parents): while True: cross_over_set = crossover(next_generation_parents) if not (cross_overs.append(cross_over_set[0])): break s_print("{} crossover with energy cost ${}".format( process_name, cross_over_set[0].total_energy_cost())) if not (cross_overs.append(cross_over_set[1])): break s_print("{} crossover with energy cost ${}".format( process_name, cross_over_set[1].total_energy_cost()))
def __do_dummy_assign(self): operating_trips = self.dump_structure.filtered_trips.copy() if self.assign_util_config.dummy_assign: if self.required_assignments > 0: for trip in operating_trips: dummy_bus = DummyBus(str(self.required_assignments)) success = self.assignment.assign(trip, dummy_bus) if success: self.required_assignments -= 1 if self.required_assignments == 0: break s_print("Dummy Missing Assignments {}".format( str(self.required_assignments)))
def finalize(self, skip_dummy=False): s_print("Expected Dummy Assignments {}".format( str(self.required_assignments))) if skip_dummy: self.__do_dummy_assign() if self.assign_util_config.compute: self.assignment.write(self.dump_structure.__key__() + "_" + self.additional_prefix) self.assignment.write_bus_stat(self.dump_structure.__key__(), self.additional_prefix, self.assign_util_config.do_print) if self.required_assignments == 0: self.assignment.complete = True
def get_obj_status(self): objective = "NA" gap = "NA" s_print("Solution status = " + str(self.solution.get_status()) + ":", end=False) status = self.solution.status[self.solution.get_status()] try: objective = round(self.solution.get_objective_value(), 5) gap = round(self.solution.MIP.get_mip_relative_gap() * 100, 2) s_print("Solution value = " + str(objective)) except cplex.exceptions.errors.CplexSolverError: s_print_err("Solution not exists exiting the program") exit(-1) return objective, status, gap
def print(self): s_print("No of Routes : {}".format(str(self._dump_config.route_limit))) s_print("No of Trips per route : {}".format( str(self._dump_config.trip_limit))) s_print("No of Electric Vehicles : {}".format( str(self._dump_config.ev_count))) s_print("No of Gas Vehicles : {}".format( str(self._dump_config.gv_count)))
def print_hf(half_count, char=stat_decorator_char, info=""): for i in range(half_count): s_print(char, end=False) if info != "": s_print(" " + info + " ", end=False) for i in range(half_count): s_print(char, end=False) s_print("")
def create_assignment(assign_type=None, dump_structure=None, args=None): if args is None: interface = "" else: interface = args.interface if issubclass(assignment_class, AssignmentWTC): if dump_structure is not None: if interface == "": assignment = AssignmentWTC(assign_type, dump_structure.charging) elif interface == "GAAction": assignment = AssignmentWTCGA(assign_type, dump_structure.charging) elif interface == "SAAction": assignment = AssignmentWTCSA(assign_type, dump_structure.charging) else: raise ValueError("Invalid interface: {}".format(interface)) else: raise DumpStructureMissingException("Dump structure is missing") elif issubclass(assignment_class, Assignment): if interface == "": assignment = Assignment(assign_type) elif interface == "GAAction": assignment = AssignmentGA(assign_type) elif interface == "SAAction": assignment = AssignmentSA(assign_type) else: raise ValueError("Invalid interface: {}".format(interface)) else: raise InvalidAssignmentClassException( "Invalid Assignment Class {}".format(assignment_class.__name__)) if assign_type == AssignTypes.GREEDY: if args is not None: s_print("Greedy configs: \nev weight: {}\ngv weight: {}".format( args.weight_ev, args.weight_gv)) assignment.set_weight(args.weight_ev, args.weight_gv) else: raise ValueError("Missing arguments") return assignment
def nearest_neighbour(assignment, swap_prob): """ Returns: nearest neighbor assignment """ swap_count = max(1, int(swap_prob * len(assignment.get_trips()))) at_least_one_swapped = False start_time = datetime.now() child = None while swap_count > 0: if (datetime.now() - start_time).total_seconds() > 4: if not at_least_one_swapped: s_print("Nothing modified breaking due to time limitation") break child, swapped = assignment.swap() if swapped: at_least_one_swapped = True swap_count -= 1 if child is None: child = assignment return child
def run(self, arg): start_time = datetime.now() self._init_population(arg) convergence_limit = 0 minimum_cost = math.inf new_population = self.sys_population generation = 0 self.summary_file_name = summary_directory + "genetic_algorithm.csv" create_dir(summary_directory) summary_file = FileWriter(self.summary_file_name) summary_file.write("iteration,energy_cost") while convergence_limit < gen_alg_convergence_limit and generation < self.generation_limit: s_print("Current Generation {}".format(str(generation))) scores = score_population(new_population) best = new_population[scores.index(min(scores))] fitness_cost = fitness(best) self.best_costs.append(fitness_cost) if fitness_cost < minimum_cost: convergence_limit = 0 minimum_cost = fitness_cost self.over_all_best = best else: convergence_limit += 1 summary_file.write([generation, minimum_cost]) new_population = select( new_population, max(int(len(new_population) * selection_ratio), min_pop)) s_print("Creating next generation ") new_population.extend(self._create_crossover(new_population)) new_population.extend(self._create_mutation(new_population)) self.population_limit = len(new_population) self.generation_count = generation generation += 1 summary_file.close() end_time = datetime.now() self.time_consumed = (end_time - start_time).total_seconds() s_print("Total time taken is " + time(int(self.time_consumed)).time) if self.over_all_best is not None: if isinstance(self.over_all_best, Assignment): self.over_all_best.write(self.dump_structure.__key__()) self.over_all_best.write_bus_stat( self.dump_structure.__key__(), do_print=True)
def run(self, dump_structure, args): cycle_count = int(args.cycle_count) start_prob = float(args.start_prob) end_prob = float(args.end_prob) swap_prob = float(args.swap_prob) swap_condition = 0 < swap_prob < 1 start_end_condition = 0 < end_prob < start_prob < 1 s_print("Simulated annealing configs: \ncycle Count: {}\nstart prob: {}\nend prob: {}\nswap prob: {}". format(args.cycle_count, args.start_prob, args.end_prob, args.swap_prob)) if not swap_condition or not start_end_condition: raise ValueError("inconsistent parameters") assignment = greedy_assign(dump_structure, AssignUtilConfig(do_print=True), args=args) energy_cost = assignment.total_energy_cost() self.min_assign = assignment self.min_cost = energy_cost temp_start = -1.0 / math.log(start_prob) temp_end = -1.0 / math.log(end_prob) rate_of_temp = (temp_end / temp_start) ** (1.0 / (cycle_count - 1.0)) selected_temp = temp_start delta_e_avg = 0.0 number_of_accepted = 1 prefix = "{}_{}_{}_".format(args.start_prob, args.end_prob, args.swap_prob) prefix = prefix.replace(".", "_") self.summary_file_name = summary_directory + prefix + "simulated_annealing.csv" create_dir(summary_directory) summary_file = FileWriter(self.summary_file_name) summary_file.write("iteration,energy_cost") summary_file.write([0, energy_cost]) for i in range(cycle_count): s_print('Cycle: {} with Temperature: {}'.format(str(i), str(selected_temp))) nn_assignment = nearest_neighbour(assignment, swap_prob) nn_energy_cost = nn_assignment.total_energy_cost() delta_e = abs(nn_energy_cost - energy_cost) if nn_energy_cost > energy_cost: if i == 0: delta_e_avg = delta_e denominator = (delta_e_avg * selected_temp) p = math.exp(-1 * math.inf) if denominator == 0 else math.exp(-delta_e / denominator) accept = True if random.random() < p else False else: accept = True # save current minimum to avoid losing details due to crash if self.min_cost > nn_energy_cost: self.min_assign = nn_assignment.copy() self.min_cost = nn_energy_cost nn_assignment.write("current_min") nn_assignment.write_bus_stat("current_min") if accept: assignment = nn_assignment energy_cost = nn_energy_cost summary_file.write([i, energy_cost]) delta_e_avg = delta_e_avg + (delta_e - delta_e_avg) / number_of_accepted number_of_accepted += 1 selected_temp = rate_of_temp * selected_temp summary_file.close() improve_perc = round(100.0 * (energy_cost - self.min_cost) / energy_cost, 3) s_print("Improvement in energy cost {}%".format(str(improve_perc)))
def schedule(self): assign_buses = self.dump_structure.all_buses().copy() operating_trips = self.dump_structure.filtered_trips.copy() self.required_assignments = len(operating_trips) assign_type = str(self.assignment.get_type()) s_print("Expected Assignments {}, Algorithm {}".format( str(self.required_assignments), assign_type)) start_time = datetime.now() if self.random_order: random.shuffle(operating_trips) else: operating_trips = sorted(operating_trips, key=lambda trip: trip.start_s()) cost_matrix = CostMatrix(self.assignment, operating_trips, assign_buses) while self.required_assignments > 0: assigned = False _bus_i = -1 _trip_i = -1 np_cost_matrix = np.array(cost_matrix.matrix) min_cost = np.min(np_cost_matrix) if min_cost == math.inf: s_print("No more feasible solutions") s_print("Remaining trips to be assigned {}".format( str(self.required_assignments))) break feasible_assign_pairs = np.argwhere(np_cost_matrix == min_cost) _trip_i, _bus_i = feasible_assign_pairs[0] _trip = operating_trips[_trip_i] _bus = assign_buses[_bus_i] if (_trip, _bus) in cost_matrix.req_charging.keys(): _charging = cost_matrix.req_charging[_trip, _bus] if self.assignment.assign_charge_force(_charging, _bus): if self.assignment.assign(_trip, _bus): assigned = True elif self.assignment.assign(_trip, _bus): assigned = True if assigned: self.required_assignments -= 1 cost_matrix.update(self.assignment, _bus_i, _trip_i) else: s_print("Not Assigned !!! No more feasible solutions") s_print("Remaining trips to be assigned {}".format( str(self.required_assignments))) break s_print("{} seconds taken for the computation".format( str((datetime.now() - start_time).total_seconds())))
def print(self): RunAssist.print(self) s_print("Slot duration : {}".format(self._dump_config.slot_duration))
def print(self, prefix=""): # print only when there is an assignment if self.duration.time_in_seconds != 0: s_print(prefix + " Duration: " + self.duration.time_h) s_print(prefix + " Assignments: " + str(self.count)) if self.kwh_energy_consumed > 0: s_print(prefix + " EV Assignments: " + str(self.electric_count)) s_print(prefix + " Energy Consumed: " + str(round(self.kwh_energy_consumed, 4)) + " kWh") if self.gallon_energy_consumed > 0: s_print(prefix + " GV Assignments: " + str(self.gasoline_count)) s_print(prefix + " Energy Consumed: " + str(round(self.gallon_energy_consumed, 4)) + " gallon(s)") energy_cost, emission = self.get_cost_and_emission() if energy_cost > 0: s_print(prefix + " Energy Cost: $" + str(round(energy_cost, 4))) if energy_cost > 0: s_print(prefix + " CO2 Emission: " + str(round(emission, 4)) + " kg")