class Random_house_sort(): ''' Random solution that doesn't violate battery capacities. ''' def __init__(self, district_id): if district_id == 1: self.district = district_1 elif district_id == 2: self.district = district_2 elif district_id == 3: self.district = district_3 elif district_id == 4: self.district = district_4 else: return False self.batteries = [] self.world = Configuration(district_id) lists = self.world.get_lists() for battery0 in lists[0]: self.batteries.append(battery0[2]) self.houses = self.district["houses"] self.costs = 0 def distribute_houses(self): ''' Associate each house with a random battery. ''' for house in self.houses: done = False negmaxcapacityleft = 0 for battery in self.batteries: negcapleft = battery.energy_production - battery.capacity if negcapleft < negmaxcapacityleft: negmaxcapacityleft = negcapleft maxcapleft = -negmaxcapacityleft if maxcapleft < house.production: return False while done == False: index = np.random.randint(0, len(self.batteries)) if self.batteries[index].capacity - self.batteries[index].energy_production > house.production: self.batteries[index].add_house(house) done = True for battery in self.batteries: self.costs += battery.costs_battery return True def reset_world(self): ''' Empties batteries (disassociates all houses from batteries). ''' for battery in self.batteries: battery.empty_battery() self.costs = 0 def run(self): ''' Runs algorithm ''' valid = False while valid == False: self.reset_world() valid = self.distribute_houses() return self.world.check50_neighbour_variant_own_costs()
class optimum_deluxe(): ''' optimum_deluxe optimizes in 3 steps. 1: connect the house that is the cheapest to a battery, repeat untill all houses are connected. 2: relocate the house that results in the lowest cost per decreased battery violation, repeat untill convergence. 3: switch the pair of houses that results in the lowest cost per decreased battery violation, repeat untill convergence. ''' def __init__(self, district_id): self.world = Configuration(district_id) def connect_house(self, world, house, battery): ''' connect house to battery the cheapest way ''' # associate house with battery and initialize list of points connected to the battery. battery.add_house(house) battery_points = [] lists = world.get_lists() # fill list of points connected to battery for battery0 in lists[0]: if battery0[2] == battery: battery_points.append([battery0[0], battery0[1]]) for cable in battery0[3]: battery_points.append(cable[0]) battery_points.append(cable[1]) # get connected point nearest to house nearest_point = [-1, -1] dist = float('inf') house_point = [house.position_x, house.position_y] for point in battery_points: dist1 = abs(house_point[0] - point[0]) + abs(house_point[1] - point[1]) if dist1 < dist: dist = dist1 nearest_point = point # make random path to nearest point x_orientation = 1 y_orientation = 1 if nearest_point[0] - house_point[0] < 0: x_orientation = -1 if nearest_point[1] - house_point[1] < 0: y_orientation = -1 x_dist = abs(nearest_point[0] - house_point[0]) y_dist = abs(nearest_point[1] - house_point[1]) current_point = house_point while x_dist + y_dist > 0: if np.random.randint(0, x_dist + y_dist) < x_dist: self.world.add_cable( self.world.configuration[current_point[0]][ current_point[1]], self.world.configuration[current_point[0] + x_orientation][current_point[1]], battery) current_point = [ current_point[0] + x_orientation, current_point[1] ] x_dist -= 1 else: self.world.add_cable( self.world.configuration[current_point[0]][ current_point[1]], self.world.configuration[current_point[0]][current_point[1] + y_orientation], battery) current_point = [ current_point[0], current_point[1] + y_orientation ] y_dist -= 1 def disconnect_house(self, world, house, battery): ''' disassociates house from battery and remove excess cable. ''' battery.remove_house(house) current_point = world.configuration[house.position_x][house.position_y] neighbours0 = self.neighbours_list(current_point, battery) neighbour_count = len(neighbours0) points_to_exclude = [[battery.position_x, battery.position_y]] for house1 in battery.houses_in_battery: points_to_exclude.append([house1.position_x, house1.position_y]) while neighbour_count == 1 and [current_point.x, current_point.y ] not in points_to_exclude: next_point = neighbours0[0] world.delete_cable(current_point, neighbours0[0], battery) current_point = next_point neighbours0 = self.neighbours_list(current_point, battery) neighbour_count = len(neighbours0) def neighbours_list(self, point, battery): ''' Returns neigbours in list format. ''' neighbours = [] if battery in point.neighbours: neighbours = point.neighbours[battery] return neighbours def check_costs_to_connect_house_to_battery(self, house, battery): ''' Checks what it would cost to connect a house to a battery. ''' costs = self.world.get_lists()[2] self.connect_house(self.world, house, battery) new_costs = self.world.get_lists()[2] self.disconnect_house(self.world, house, battery) return new_costs - costs def get_disconnected_houses_and_all_batteries(self, world): ''' Returns lists of house that are not connected to a battery and all batteries. ''' lists = world.get_lists() houses0 = lists[1] batteries0 = lists[0] houses = [] batteries = [] for house in houses0: houses.append(house[2]) houses2 = [] for battery1 in batteries0: battery = battery1[2] batteries.append(battery) houses_in_battery = battery.houses_in_battery for house2 in houses_in_battery: houses2.append(house2) houses3 = [] for house4 in houses: if house4 not in houses2: houses3.append(house4) return houses3, batteries def connect_cheapest_house(self): ''' Connect the house that is the cheapest to connect. ''' houses, batteries = self.get_disconnected_houses_and_all_batteries( self.world) if len(houses) == 0: return False else: house0 = None battery0 = None cost = float('inf') for house in houses: for battery in batteries: cost1 = self.check_costs_to_connect_house_to_battery( house, battery) if cost1 < cost: house0 = house battery0 = battery cost = cost1 self.connect_house(self.world, house0, battery0) print(self.world.get_lists()[2]) print(self.world.check('Optimum Deluxe')) print(self.world.text_grid()) return True def connect_all_houses(self): ''' Connect the cheapest house untill all houses are connected. ''' while self.connect_cheapest_house(): pass def check_costs_to_relocate_house(self, house, battery_1, battery_2): ''' Check what it would cost to relocate a battery to another battery and what the decrease of the battery capacity violation would be. ''' old_costs = self.world.get_lists()[2] old_bat_violation = self.world.check('Optimum Deluxe')[4] self.disconnect_house(self.world, house, battery_1) self.connect_house(self.world, house, battery_2) new_costs = self.world.get_lists()[2] new_bat_violation = self.world.check('Optimum Deluxe')[4] bat_gained = old_bat_violation - new_bat_violation extra_costs = new_costs - old_costs self.disconnect_house(self.world, house, battery_2) self.connect_house(self.world, house, battery_1) return bat_gained, extra_costs def do_best_relocation_of_house(self): ''' Relocate the house that results in the lowest cost per decreased battery violation. ''' # initialize lists and variables. houses, batteries = self.get_disconnected_houses_and_all_batteries( self.world) battery0_1 = None battery0_2 = None house0 = None min_cost_per_bat_gained = float('inf') # find smallest cost per battery violation descent. for i in range(len(batteries)): for house in batteries[i].houses_in_battery: for j in range(len(batteries)): if (j != i): bat_gained, extra_costs = self.check_costs_to_relocate_house( house, batteries[i], batteries[j]) if bat_gained > 0: cost_per_bat_gained = extra_costs / bat_gained if cost_per_bat_gained < min_cost_per_bat_gained: battery0_1 = batteries[i] battery0_2 = batteries[j] house0 = house min_cost_per_bat_gained = cost_per_bat_gained # perform the relocation if the battery violation descent is greater than zero, otherwise return False. if battery0_1 == None: return False else: self.disconnect_house(self.world, house0, battery0_1) self.connect_house(self.world, house0, battery0_2) print(self.world.get_lists()[2]) print(self.world.check('Optimum Deluxe')) print(self.world.text_grid()) return True def relocate_untill_convergence(self): ''' Relocate houses untill convergence. ''' while self.do_best_relocation_of_house(): pass def switch_houses(self, world, battery_1, house_1, battery_2, house_2): ''' Switches houses (between two batteries). ''' self.disconnect_house(world, house_1, battery_1) self.disconnect_house(world, house_2, battery_2) self.connect_house(world, house_1, battery_2) self.connect_house(world, house_2, battery_1) def check_costs_to_switch_houses(self, battery_1, house_1, battery_2, house_2): ''' Checks what it would cost to switch two houses between batteries. ''' old_costs = self.world.get_lists()[2] old_bat_violation = self.world.check('Optimum Deluxe')[4] self.switch_houses(self.world, battery_1, house_1, battery_2, house_2) new_costs = self.world.get_lists()[2] new_bat_violation = self.world.check('Optimum Deluxe')[4] bat_gained = old_bat_violation - new_bat_violation extra_costs = new_costs - old_costs self.switch_houses(self.world, battery_2, house_1, battery_1, house_2) return bat_gained, extra_costs def do_best_switch_of_houses(self): ''' Perform the switch of houses that results in the lowest cost per decreased battery violation. ''' # initialize lists and variables. houses, batteries = self.get_disconnected_houses_and_all_batteries( self.world) battery0_1 = None battery0_2 = None house0_1 = None house0_2 = None min_cost_per_bat_gained = float('inf') # find smallest cost per battery violation descent. for i in range(len(batteries)): houses_3 = copy.copy(batteries[i].houses_in_battery) for house_1 in houses_3: for j in range(len(batteries)): if (j != i): houses_4 = copy.copy(batteries[j].houses_in_battery) for house_2 in houses_4: bat_gained, extra_costs = self.check_costs_to_switch_houses( batteries[i], house_1, batteries[j], house_2) if bat_gained > 0: cost_per_bat_gained = extra_costs / bat_gained if cost_per_bat_gained < min_cost_per_bat_gained: battery0_1 = batteries[i] battery0_2 = batteries[j] house0_1 = house_1 house0_2 = house_2 min_cost_per_bat_gained = cost_per_bat_gained # perform the relocation if the battery violation descent is greater than zero, otherwise return False. if battery0_1 == None: return False else: self.switch_houses(self.world, battery0_1, house0_1, battery0_2, house0_2) print(self.world.get_lists()[2]) print(self.world.check('Optimum Deluxe')) print(self.world.text_grid()) return True def switch_houses_until_convergence(self): ''' Switch houses untill battery violation is zero. ''' while self.do_best_switch_of_houses(): pass def run(self): ''' Runs algorithm and returns result in check50 format. ''' self.connect_all_houses() self.relocate_untill_convergence() self.switch_houses_until_convergence() return self.world.check50_neighbour_variant()