コード例 #1
0
def test_edge_recombination_crossover(graph):
    parent1 = Tour(is_random=True)
    parent2 = Tour(is_random=True)

    child1, child2 = co.crossover_edge_recombination(parent1, parent2)

    assert sorted(child1.path) == sorted(Graph.nodes)
    assert sorted(child2.path) == sorted(Graph.nodes)
コード例 #2
0
def test_crossover(graph):
    parent1 = Tour(is_random=True)
    parent2 = Tour(is_random=True)

    child1, child2 = GA._crossover(parent1, parent2)

    assert sorted(child1.path) == sorted(Graph.nodes)
    assert sorted(child2.path) == sorted(Graph.nodes)
コード例 #3
0
def test_CX2_crossover():
    nodes = [Node(i + 1) for i in range(8)]
    distance_matrix = DistanceMatrix(8)

    Graph.set_graph(nodes, distance_matrix)
    # parent1 = Tour(path=[3,4,8,2,7,1,6,5])
    # parent2 = Tour(path=[4,2,5,1,6,8,3,7])
    # parent1 = Tour(path=[1,2,3,4,5,6,7,8])
    # parent2 = Tour(path=[2,7,5,8,4,1,6,3])
    parent1 = Tour(path=[7, 6, 3, 8, 5, 1, 4, 2])
    parent2 = Tour(path=[3, 8, 2, 4, 5, 1, 7, 6])
    child1, child2 = co.crossover_CX2(parent1, parent2)

    assert sorted(child1.path) == sorted(nodes)
    assert sorted(child2.path) == sorted(nodes)
コード例 #4
0
    def solve_GA(problem, generations):
        Graph.set_graph(problem.nodes, problem.distance_matrix)

        tours = []
        seed = Tour(path=solve_greedy(problem))
        tours.append(seed)
        for _ in range(population_size - 1):
            tour = copy.deepcopy(seed)
            mu.mutate_swap_connections(tour, mutation_rate=1)

            tours.append(tour)

        population = Population(population_size, tours=tours)

        for i in range(generations):
            logging.info('\n{}th generation'.format(i))

            if verbose:
                print('{}th generation'.format(i))

            population = GA.evolve_population(population)

            best_tour = population.get_fittest()
            logging.info('distance: {}'.format(best_tour.distance))

            if verbose:
                print('distance: {}\n'.format(best_tour.distance))

        best_tour = population.get_fittest()

        return best_tour.path, best_tour.distance
コード例 #5
0
def test_mutate(graph):
    tour = Tour(is_random=True)

    old_tour = copy.deepcopy(tour)

    mu.mutate_swap_connections(tour, mutation_rate=1, only_better=False)

    print(old_tour)
    print(tour)
    assert sorted(old_tour.path) == sorted(tour.path)
コード例 #6
0
def crossover_order(parent1: Tour, parent2: Tour) -> (Tour, Tour):
    child1 = Tour()
    child2 = Tour()
    N = Graph.num_nodes

    start_index = random.randint(0, N)
    end_index = random.randint(0, N)

    if start_index > end_index:
        temp = start_index
        start_index = end_index
        end_index = temp

    node_ids1 = []
    node_ids2 = []

    for i in range(start_index, end_index):
        node1 = parent1.get_node(i)
        node_ids1.append(node1.id)

        node2 = parent2.get_node(i)
        node_ids2.append(node2.id)

        child1.add_node(i, node1)
        child2.add_node(i, node2)

    def binary_search(target, data):
        data.sort()
        start = 0
        end = len(data) - 1

        while start <= end:
            mid = (start + end) // 2

            if data[mid] == target:
                return True
            elif data[mid] < target:
                start = mid + 1
            else:
                end = mid - 1

        return False

    remaining_indices = list(range(end_index, N)) + \
        list(range(0, start_index))

    offset1 = 0
    offset2 = 0

    indices = list(range(0, N))
    cyclic_indices = indices[end_index:N] + indices[0:end_index]

    for i in cyclic_indices:
        node1 = parent2.get_node(i)
        node2 = parent1.get_node(i)
        # if child1.contains_node(node):
        if not binary_search(node1.id, node_ids1):
            child1.add_node(remaining_indices[offset1], node1)
            offset1 += 1

        if not binary_search(node2.id, node_ids2):
            child2.add_node(remaining_indices[offset2], node2)
            offset2 += 1

    child1.update_distance()
    child2.update_distance()

    return child1, child2
コード例 #7
0
def crossover_CX2(parent1: Tour, parent2: Tour) -> (Tour, Tour):
    # TODO: Need Refactoring

    child1 = Tour()
    child2 = Tour()

    visited_p1 = [False] * Graph.num_nodes
    visited_p2 = [False] * Graph.num_nodes
    child_index = 0

    p1 = parent1
    p2 = parent2

    remaining_c1 = []
    remaining_c2 = []

    while True:
        if len(visited_p2) == 0:
            # Corner case: no cycle in a step
            for i in range(len(remaining_c1)):
                child1.add_node(-i - 1, Graph.nodes_by_id[remaining_c1[i]])

            for i in range(len(remaining_c2)):
                child2.add_node(-i - 1, Graph.nodes_by_id[remaining_c2[i]])

            return child1, child2

        # Step 2
        node = p2.get_node(0)
        visited_p2[0] = True
        child1.add_node(0 + child_index, node)

        # Step 3:
        pos = p1.id_to_position[node.id]
        visited_p1[pos] = True
        pos2 = p1.id_to_position[p2.get_node(pos).id]

        node2 = p2.get_node(pos2)
        visited_p2[pos2] = True
        child2.add_node(0 + child_index, node2)

        i = 1
        c1_nodes = [node.id]
        c2_nodes = [node2.id]

        while i + child_index < Graph.num_nodes:
            if node2.id == p1.get_node(0).id:
                visited_p1[0] = True
                if len(set(c1_nodes) - set(c2_nodes)) != 0:
                    for id in c1_nodes:
                        if id in c2_nodes:
                            continue
                        remaining_c2.append(id)

                    for id in c2_nodes:
                        if id in c1_nodes:
                            continue
                        remaining_c1.append(id)

                break

            # Step 4:
            pos = p1.id_to_position[node2.id]
            visited_p1[pos] = True
            node = p2.get_node(pos)

            visited_p2[pos] = True

            child1.add_node(i + child_index, node)
            c1_nodes.append(node.id)

            # Repeat Step 3:
            pos = p1.id_to_position[node.id]
            visited_p1[pos] = True

            pos2 = p1.id_to_position[p2.get_node(pos).id]
            node2 = p2.get_node(pos2)

            visited_p2[pos2] = True

            child2.add_node(i + child_index, node2)
            c2_nodes.append(node2.id)

            i += 1

            if node2.id == p1.get_node(0).id:
                visited_p1[0] = True
                if len(set(c1_nodes) - set(c2_nodes)) != 0:
                    for id in c1_nodes:
                        if id in c2_nodes:
                            continue
                        remaining_c2.append(id)
                    for id in c2_nodes:
                        if id in c1_nodes:
                            continue
                        remaining_c1.append(id)

                break

        child_index += i
        if child_index == Graph.num_nodes:
            return child1, child2

        new_p1 = Tour()
        new_p2 = Tour()

        i1 = 0
        i2 = 0
        for pos in range(len(visited_p1)):
            if not visited_p1[pos]:
                new_p1.add_node(i1, p1.get_node(pos))
                i1 += 1
            if not visited_p2[pos]:
                new_p2.add_node(i2, p2.get_node(pos))
                i2 += 1

        assert i1 == i2

        visited_p1 = [False] * i1
        visited_p2 = [False] * i2

        p1 = new_p1
        p2 = new_p2
コード例 #8
0
def crossover_edge_recombination(parent1: Tour, parent2: Tour) -> (Tour, Tour):
    # Adjacency Information
    # Node 1 -> (-9, 2, 4)
    # Node 2 -> (1, -3, 5)
    # (-) for both adjacent element
    adjacency = {}
    for i in range(Graph.num_nodes):
        node = parent1.get_node(i)
        adjacency[node.id] = [
            parent1.get_node(i - 1).id,
            parent1.get_node(i + 1).id
        ]

    for i in range(Graph.num_nodes):
        node = parent2.get_node(i)
        ids = [parent2.get_node(i - 1).id, parent2.get_node(i + 1).id]

        neighbors = adjacency[node.id]

        for id in ids:
            if id in neighbors:
                i = neighbors.index(id)
                adjacency[node.id][i] = -1 * neighbors[i]
            else:
                adjacency[node.id].append(id)

    adjacencies = [adjacency, copy.deepcopy(adjacency)]

    parents = [parent1, parent2]
    children = [Tour(), Tour()]

    def select_neighbor_id(prev_id, adjacency):
        ids = adjacency[prev_id]
        selected_id = []
        for id in ids:
            if id < 0:
                selected_id = [-id]
                break

        if len(selected_id) == 0:
            min_num_neighbors = 10**10
            for id in ids:
                if min_num_neighbors > len(adjacency[id]):
                    selected_id = [id]
                    min_num_neighbors = len(adjacency[id])
                if min_num_neighbors == len(adjacency[id]):
                    selected_id.append(id)

        if len(selected_id) == 0:
            min_num_neighbors = 10**10
            for id in adjacency.keys():
                if id == prev_id:
                    continue
                if min_num_neighbors > len(adjacency[id]):
                    selected_id = [id]
                    min_num_neighbors = len(adjacency[id])
                if min_num_neighbors == len(adjacency[id]):
                    selected_id.append(id)

        assert len(selected_id) != 0

        if len(selected_id) > 1:
            return selected_id[random.randint(0, len(selected_id) - 1)]
        return selected_id[0]

    def delete_node_from_all_neighbors(prev_id, adjacency):
        for id in adjacency.keys():
            try:
                adjacency[id].remove(prev_id)
            except ValueError:
                pass
            try:
                adjacency[id].remove(-1 * prev_id)
            except ValueError:
                pass

    def delete_node_from_table(prev_id, adjacency):
        del adjacency[prev_id]

    for i in range(2):
        child = children[i]
        parent = parents[i]

        adjacency = adjacencies[i]

        child.add_node(0, parent.get_node(0))
        prev_id = child.get_node(0).id

        for i in range(1, Graph.num_nodes):
            delete_node_from_all_neighbors(prev_id, adjacency)

            selected_id = select_neighbor_id(prev_id, adjacency)
            delete_node_from_table(prev_id, adjacency)
            child.add_node(i, Graph.get_node(selected_id))

            prev_id = selected_id

    return children[0], children[1]