def greedy_lookahead(grid, N=4, break_n=500):
    """
    Greedy lookahead will find the house with the shortest distance to a battery
    When a batteries current capacity goes between a certain range the algortim will call the look function
    This look function will look at all possible combinations of houses to fill this battery
    Look will return the combination of houses with the shortest distance
    N =  the average amount of houses you wish to look ahead
    break_n =  is the number of iterations you want the algorithm to try finding a solution
    """
    # initiate counter that will determine when to break
    counter = 0

    # get all outputs
    all_outputs = [house.max_output for house in grid.unconnected_houses]

    # repeat till solution is found
    while grid.unconnected_houses != []:

        # best_dist is the best score on distance
        best_dist = float('inf')

        # loop over houses that are not connected
        for house in grid.unconnected_houses:

            #  finds the lowest distance to battery for each house
            # select the house with the lowest distance
            lowest_dist_house = float('inf')
            for battery in grid.batteries:
                dist = distance(house.location, battery.location)
                if dist < lowest_dist_house and battery.current_capacity > house.max_output and battery.current_capacity > np.mean(
                        all_outputs) * N:
                    bat_id = battery.id
                    house_id = house.id
                    lowest_dist_house = dist
                elif min(all_outputs) < battery.current_capacity < np.mean(
                        all_outputs) * N:
                    if 0 < grid.range_connected(battery)[1] < 8:
                        houses = look(grid, battery)
                        for h in houses:
                            grid.connect(h.id, battery.id)

            if lowest_dist_house < best_dist:
                connect_bat_id = bat_id
                connect_house_id = house_id
                best_dist = lowest_dist_house

        # connect house with lowest distance to closest battery
        grid.connect(connect_house_id, connect_bat_id)

        # break if stuck in infinit loop after certain n
        counter += 1
        if counter > break_n:
            break

    # fill remaining grid if needed
    if grid.unconnected_houses != []:
        grid = Algoritmes.greedy(grid)

    return grid
def look(grid, battery):
    """
    Look will find the best combination of houses to fill the current capacity of input battery,
    with the shortest total distance
    """
    # get min and max of houses able to connect to battery
    range_con = grid.range_connected(battery)

    # initiate
    lowest_combination = [0, 0]
    all_outputs = [house.max_output for house in grid.unconnected_houses]
    best_dist = float('inf')
    out_houses = []

    # in range of able to connect houses generate all possible combinations of house outputs
    for i in range(range_con[1]):

        # generate combination
        combinations = itertools.combinations(all_outputs, i)

        # find lowest combination
        for combi in combinations:
            if 0 < battery.current_capacity - sum(
                    combi) < battery.current_capacity - sum(
                        lowest_combination) and battery.current_capacity - sum(
                            combi) < 5:

                # find houses
                houses = []
                for output in combi:
                    for house in grid.unconnected_houses:
                        if house.max_output == output:
                            houses.append(house)

                # calculate total distance
                total_dist = 0
                for h in houses:
                    total_dist += distance(h.location, battery.location)

                # if current combination has better distance save combination
                if total_dist < best_dist:
                    best_dist = total_dist
                    lowest_combination = combi
                    out_houses = houses

    return out_houses
示例#3
0
    def find_closest_house(self, houses):
        """
        Finds the closest house to this battery in input list
        """
        # initiate distance to infinity and have no houses as closest
        smallest_distance = float('inf')
        smallest_distance_house = None

        # loop over houses to find closest house
        # checks if this house can fit current capcity of the battery
        for house in houses:
            dist = distance(house.location, self.location)
            if self.current_capacity > house.max_output:
                if dist < smallest_distance:
                    smallest_distance = dist
                    smallest_distance_house = house

        if smallest_distance_house == None:
            # print(f"No shortest distance found, probably because battery capacity is full. current capcity: {self.current_capacity}")
            return
        return smallest_distance_house
示例#4
0
def greedy_alt(grid):
    """
    Alternative greedy algorithm that connects houses in order of
    output (high to low)
    """
    def max_output_func(house):
        """
        returns max output of a specified house.
        """
        return house.max_output

    counter = 0
    while grid.unconnected_houses != []:
        # sort houses from largest to smallest
        grid.unconnected_houses.sort(key=max_output_func, reverse=True)

        for house in grid.unconnected_houses:
            # for the unconnected_houses, intialize the distance to infinity
            # and make sure it doen't have a closet battery
            smallest_dist = float('inf')
            closest_battery_id = None

            # if there is capacity left, connect the house to closet battery
            for battery in grid.batteries:
                dist = distance(house.location, battery.location)
                if dist < smallest_dist and battery.current_capacity > house.max_output:
                    closest_battery_id = battery.id
                    smallest_dist = dist
            grid.connect(house.id, closest_battery_id)
        counter += 1
        if counter > MAX_ITERATIONS:
            break

    # fill last part with the other greedy if needed
    if grid.unconnected_houses != []:
        grid = Algoritmes.greedy(grid)

    return grid
示例#5
0
def hillclimber_greedy(grid):
    """
    This hillclimber algoritm checks if a swap between two houses can be made,
    and if so, if the swap would shorten the length of the path, if this is
    the case, the swap is made.

    Requires the grid as input.
    """

    # set swap to true to start the loop
    swap = True

    # loops until no swaps can be made
    while swap == True:
        # sets swap to false
        swap = False
        # loops through the batteries
        for b1 in grid.batteries:
            # loops through the houses in the batteries
            for h1 in b1.routes:
                # loops through the batteries
                for b2 in grid.batteries:
                    # loops through the houses in the batteries
                    for h2 in b2.routes:
                        b1cap = h1.house.max_output + b1.current_capacity
                        b2cap = h2.house.max_output + b2.current_capacity
                        # checks if a swap between two houses can be made
                        if h1.house.max_output < b2cap and h2.house.max_output < b1cap:
                                # calculate is the swap improves the length of the connections
                                len_new =  distance(h1.house.location, b2.location) + distance(h2.house.location, b1.location)
                                len_old = h1.length + h2.length

                                # makes the swap if the length is improved
                                if swap == False and len_new < len_old and h1.house.id != h2.house.id:
                                    swap = grid.swap(h1, h2)
                                    break
    return grid
示例#6
0
    def upper_bound(self):
        """
        Calculates the upper_bound based on the manhattan distance for the longest path
        for each house.
        Returns the total grid cost of the upper_bound
        """
        all_longest = []
        # loop over houses for each house loop over batteries
        # find the longest distance to a battery and append to output list
        for house in self.houses:
            current_house_longest = float('-inf')
            for battery in self.batteries:
                dist = distance(house.location, battery.location)
                if dist > current_house_longest:
                    current_house_longest = dist
            all_longest.append(current_house_longest)

        # calculate lower bound costs
        upper_bound = 0
        for battery in self.batteries:
            upper_bound += battery.cost
        upper_bound += sum(all_longest) * 9

        return upper_bound
def hillclimber_greedy_double_swap(grid):
    """
    This hillclimber algoritm checks if a swap between pairs of two houses can be made,
    and if so, if the swap would shorten the length of the path, if this is
    the case, the swap is made.
    """
    swap = True
    # loops until no swaps can be made
    while swap == True:
        # sets swap to false
        swap = False
        grid = Algoritmes.hillclimber_greedy(grid)
        # loops through the batteries
        for b1 in grid.batteries:
            for h1 in b1.routes:
                for h2 in b1.routes:
                    for b2 in grid.batteries:
                        for h3 in b2.routes:
                            for h4 in b2.routes:

                                h1h2 = h1.house.max_output + h2.house.max_output
                                h3h4 = h3.house.max_output + h4.house.max_output
                                cap1 = h1h2 + b1.current_capacity
                                cap2 = h3h4 + b2.current_capacity

                                if h1 != h2 and h3 != h4 and h1h2 < cap2 and h3h4 < cap1:

                                    len_old = h1.length + h2.length + h3.length + h4.length

                                    # Find battery ids
                                    bat1Index = None
                                    bat3Index = None
                                    for idx, battery in enumerate(
                                            grid.batteries):
                                        if battery.id == h1.battery_id:
                                            bat1Index = idx
                                        if battery.id == h3.battery_id:
                                            bat3Index = idx

                                    # get all distances
                                    d1 = distance(
                                        h1.house.location,
                                        grid.batteries[bat3Index].location)
                                    d2 = distance(
                                        h2.house.location,
                                        grid.batteries[bat3Index].location)
                                    d3 = distance(
                                        h3.house.location,
                                        grid.batteries[bat1Index].location)
                                    d4 = distance(
                                        h4.house.location,
                                        grid.batteries[bat1Index].location)

                                    len_new = d1 + d2 + d3 + d4

                                    # makes the swap if the length is improved
                                    if swap == False and len_new < len_old:

                                        swap = grid.swap(h1, h2, h3, h4)
                                        break
    return grid
def re_arrange(grid):
    """
    Re-arrange for simulated_annealing
    """

    found = False
    house1 = False

    while found == False:

        # get random house_ids
        r1 = random.randint(1, 150)
        r2 = random.randint(1, 150)

        # find house 1
        while house1 == False:
            for battery in grid.batteries:
                for route in battery.routes:
                    if route.house.id == r1:

                        # save house 1 and battery 1
                        h1 = route
                        b1 = battery
                        max1 = h1.house.max_output + b1.current_capacity
                        house1 = True
                        break

        # find house 2
        for battery in grid.batteries:
            for route in battery.routes:
                if route.house.id == r2:

                    # save house 1 and battery 1
                    h2 = route
                    b2 = battery
                    max2 = h2.house.max_output + b2.current_capacity

                    # Find battery ids
                    bat1Index = None
                    bat2Index = None
                    for idx, battery in enumerate(grid.batteries):
                        if battery.id == h1.battery_id:
                            bat1Index = idx
                        if battery.id == h2.battery_id:
                            bat2Index = idx

                    # if swap is possible, swap
                    if h1.house.max_output < max2 and h2.house.max_output < max1 and h1.battery_id != h2.battery_id:

                        # calculate is the swap improves the length of the connections
                        h1len = distance(h1.house.location,
                                         grid.batteries[bat2Index].location)
                        h2len = distance(h2.house.location,
                                         grid.batteries[bat1Index].location)
                        lengte_new = h1len + h2len
                        lengte_old = h1.length + h2.length

                        # stop while loop
                        found = True
                        break

        # in case we cannot find a house to swap with house 1, we need to reset the loop
        # without this you might get stuck in a loop
        house1 = False

    # return all the necessary information
    proposed = (lengte_new - lengte_old) * 9
    h1 = h1
    h2 = h2

    return proposed, h1, h2