コード例 #1
0
ファイル: solver.py プロジェクト: Lyrianna/ero1-2023
def solve(initial_graph):

    """Create ajd list graph for later"""
    euler_graph = multi_graph.MultiGraph(edges=initial_graph.edge_list())

    """Find odd degree nodes"""
    odd_degree_nodes = euler_graph.odd_degree_nodes()

    print(f'{len(odd_degree_nodes)} odd_degree_nodes =', odd_degree_nodes)

    """Compute all possible odd node pairs"""
    odd_node_pairs = list(itertools.combinations(odd_degree_nodes, 2))
    odd_node_pairs = [utils.normalize_pair(*p) for p in odd_node_pairs]
    print(f'{len(odd_node_pairs)} odd node pairs')

    """Compute the minimum distance for every pair"""
    print('computing odd node pairs shortest paths...')
    tstart = datetime.now()
    csr_mat = scipy.sparse.csr_matrix(initial_graph.mat)
    dist_matrix = shortest_path(csr_mat, directed=False, return_predecessors=False)  # Dist matrix of the whole graph
    tend = datetime.now()
    print('done, took', tend - tstart)

    odd_node_pairs_distance_list = []  # (u, v, d)
    for pair in odd_node_pairs:
        u, v = pair
        odd_node_pairs_distance_list.append((u, v, dist_matrix[u, v]))

    """Create a complete graph of those pairs with the minimum distance as weight"""
    print('creating euler graph')
    graph_odd_complete = Graph(odd_node_pairs_distance_list)

    """Compute the minimum weight matching"""
    print('computing minimum weight matching...')
    tstart = datetime.now()
    min_weight_pairs = edmonds.min_weight_matching(graph_odd_complete)
    tend = datetime.now()
    print('done, took', tend - tstart)
    print(f'{len(min_weight_pairs)} min_weight_pairs =', min_weight_pairs)

    """Built up the euleur graph (initial graph + "fake" edges between the pairs found in previous computation)"""
    for pair in min_weight_pairs:
        u, v = utils.normalize_pair(*pair)
        dist = dist_matrix[u, v]
        euler_graph.add_edge(*pair, dist)

    """Get a naive path (naive because it uses the previous fakes edges)"""
    naive_euler_circuit = list(euler.eulerian_circuit(euler_graph))
    print(naive_euler_circuit)

    """Create the real final path by replacing the fake edges with the shortest possible path"""
    final_path = []
    for edge in naive_euler_circuit:
        if initial_graph.has_edge(*edge):
            final_path.append(edge)
        else:
            real_path, _ = initial_graph.shortest_path(csr_mat, *edge)
            final_path += real_path

    return final_path
コード例 #2
0
ファイル: graph.py プロジェクト: Lyrianna/ero1-2023
 def remove_node(self, node_id):
     node = self.nodes.get(node_id)
     if node is None:
         return
     for neighbour_id, neighbour in node.neighbours.items():
         del neighbour.node.neighbours[
             node_id]  # Remove neighbours ref to this node
         self.edges.pop(utils.normalize_pair(node_id, neighbour_id),
                        None)  # Remove the edge from the graph
     self.degree -= 1
     del self.nodes[node_id]
コード例 #3
0
 def get_edge_color(path, u, v, highlight_last=False):
     if highlight_last and (
         (u, v) == path[-1] or
         (v, u) == path[-1]):  # Highlight last visited edge
         return 'yellow'
     if visit_times.get(utils.normalize_pair(u, v),
                        0) > 1:  # Already visited edge
         return 'blue'
     if (u, v) in path or (v, u) in path:  # Visited edge
         return 'red'
     return 'w'
コード例 #4
0
ファイル: graph.py プロジェクト: Lyrianna/ero1-2023
    def add_edge(self, u, v, weight):  # Undirected for now

        # Get (or create if necessary) the two nodes
        start_node = self.add_node(u)
        end_node = self.add_node(v)

        # Link the two nodes
        start_node.add_neighbour(end_node)
        end_node.add_neighbour(start_node)

        key = utils.normalize_pair(u, v)
        self.edges[key] = weight
コード例 #5
0
ファイル: graph.py プロジェクト: Lyrianna/ero1-2023
    def remove_edge(self, u, v):

        # Check if edge actually exists
        key = utils.normalize_pair(u, v)
        edge = self.edges.pop(key, None)
        if edge is None:
            return

        # If so, remove link between each node
        del self.nodes[u].neighbours[v]  # Remove neighbouring ref u -> v
        del self.nodes[v].neighbours[u]  # Remove neighbouring ref v -> u

        # Remove the edge from the graph
        del self.edges[key]
コード例 #6
0
ファイル: graph.py プロジェクト: Lyrianna/ero1-2023
 def get_edge(self, u, v):  # No checks!
     return self.edges[utils.normalize_pair(u, v)]
コード例 #7
0
ファイル: graph.py プロジェクト: Lyrianna/ero1-2023
 def has_edge(self, u, v):
     return utils.normalize_pair(u, v) in self.edges
コード例 #8
0
def render_path_as_gif(initial_graph_edges,
                       path,
                       img_size=1000,
                       duration_between_steps=0.8,
                       edge_batch_size=1):
    """
    Render final path as a gif (optional)
    """
    ga = gvanim.Animation()
    for edge in initial_graph_edges:
        ga.add_edge(edge[0], edge[1])
    ga.next_step()

    visit_times = {}
    for edge in path:
        edge = utils.normalize_pair(*edge)
        visit_times[edge] = 0

    drawn_path = []

    def draw_path():
        for edge in drawn_path:
            if visit_times[edge] > 1:
                ga.highlight_edge(*edge, color='blue')
            else:
                ga.highlight_edge(*edge, color='red')

    # for raw_edge in path:
    #     new_edge = utils.normalize_pair(*raw_edge)
    #     draw_path()
    #     ga.highlight_edge(*new_edge, color='red')
    #     drawn_path.append(new_edge)
    #     visit_times[new_edge] += 1
    #     ga.next_step()

    cs = edge_batch_size  # Chunk size to process paths by
    for chunk in [
            path[cs * i:cs * (i + 1)] for i in range(len(path) // cs + 1)
    ]:
        for raw_edge in chunk:
            new_edge = utils.normalize_pair(*raw_edge)
            drawn_path.append(new_edge)
            visit_times[new_edge] += 1
        draw_path()
        ga.highlight_edge(*drawn_path[-1],
                          color='yellow')  # Mark last visited edge in red
        ga.next_step()

    # Final result
    draw_path()
    ga.next_step()

    render_directory = 'render_files'
    os.makedirs(render_directory)

    ga_graphs = ga.graphs()
    files = gvanim.render(ga_graphs,
                          f'{render_directory}/step',
                          'png',
                          size=img_size)
    render_filename = 'render.gif'
    with imageio.get_writer(render_filename,
                            mode='I',
                            duration=duration_between_steps) as writer:
        for file in files:
            image = imageio.imread(file)
            writer.append_data(image)

    print(
        f'Final path rendering available at "src/theoric_app/{render_filename}"'
    )
コード例 #9
0
def render_osmnx_path(osmnx_graph,
                      edge_path,
                      duration_between_steps=0.5,
                      step_size=1,
                      edge_width=1.0):

    time_stamp = int(time.time())
    output_dir = f'render_files_{time_stamp}'
    os.makedirs(output_dir)

    visit_times = {}
    for edge in edge_path:
        visit_times[utils.normalize_pair(*edge)] = 0

    def get_edge_color(path, u, v, highlight_last=False):
        if highlight_last and (
            (u, v) == path[-1] or
            (v, u) == path[-1]):  # Highlight last visited edge
            return 'yellow'
        if visit_times.get(utils.normalize_pair(u, v),
                           0) > 1:  # Already visited edge
            return 'blue'
        if (u, v) in path or (v, u) in path:  # Visited edge
            return 'red'
        return 'w'

    def get_edge_colors(path, highlight_last=False):
        return [
            get_edge_color(path, u, v, highlight_last)
            for (u, v) in osmnx_graph.edges()
        ]

    files = []

    def render_path(path, filename, highlight_last=False):
        edge_colors = get_edge_colors(path, highlight_last)
        ox.plot_graph(osmnx_graph,
                      node_color='w',
                      node_edgecolor='k',
                      node_size=0,
                      node_zorder=3,
                      edge_color=edge_colors,
                      edge_linewidth=edge_width,
                      show=False,
                      close=True,
                      save=True,
                      filepath=filename)
        files.append(filename)

    # # Render step by step
    # for i in range(len(edge_path)):
    #     current_path = edge_path[:(i + 1)]
    #     render_path(current_path, f'{output_dir}/step_{i:05}.png', highlight_last=True)
    #     visit_times[utils.normalize_pair(*edge_path[i])] += 1  # Update last visited pair

    # Render by big steps
    for i in range(len(edge_path) // step_size + 1):
        start_i, end_i = step_size * i, step_size * (i + 1)
        current_path = edge_path[:end_i]
        render_path(current_path,
                    f'{output_dir}/step_{i:05}.png',
                    highlight_last=True)
        for edge in edge_path[start_i:end_i]:
            visit_times[utils.normalize_pair(*edge)] += 1

    # Render final step
    render_path(edge_path, f'{output_dir}/step_{len(edge_path)}.png')

    print(files)

    # Render final gif
    with imageio.get_writer(f'osmnx_render_{time_stamp}.gif',
                            mode='I',
                            duration=duration_between_steps) as writer:
        for file in files:
            image = imageio.imread(file)
            writer.append_data(image)

    print(output_dir)