#!/usr/bin/env python
# coding: utf-8

# In[4]:


# Diapo 22

N = [0,1,2,3,4,5,6,7,8]
E = [(0,5), (0,7), (5,7), (5,3) , (3,6), (3,2), (7,3), (7,8), (7,1), (7,4), (4,8), (5,1)]

# First, and for the sake of simplification, we will count the number of
# segments / edges separating different points / nodes (of a graph)

counted = [ [] for i in range(len(N))]

for e in E:
    if e[0] != e[1]:
        if e[0] not in counted[e[1]]:
            counted[e[1]].append(e[0])
        if e[1] not in counted[e[0]]:
            counted[e[0]].append(e[1])

# Print counted
for i in range(len(N)):
    print("Node", i, ":", counted[i])

# We want to write a program which, given a subset of these nodes
# and edges, computes the list of nodes ordered in ascending order
# of distances to a given particular node.
# » For node 0 and the subset N0 = {1,3,4,5,7} and the associated edges E0 = {(0,5),
# (0,7), (5,7), (7, 3), (7,1), (7,4), (5,1)}
# and the expected result is L0 = {0,5,7,1,3,4}


# In[9]:


# Generate matrix from nodes and edges
def graph_to_matrix(N, E):
    M = [ [0 for i in range(len(N))] for j in range(len(N))]
    for e in E:
        M[e[0]][e[1]] = 1
        M[e[1]][e[0]] = 1
    return M

# Print matrix
matrix = graph_to_matrix(N, E)
for i in range(len(N)):
    print(matrix[i])


# In[6]:


def transitive_closure(matrix):
    modification = True
    while modification:
        modification = False
        for i in range(len(matrix)):
            for j in range(len(matrix)):
                for k in range(len(matrix)):
                    if matrix[i][j] > 0 and matrix[j][k] > 0 and matrix[i][k] == 0:
                        matrix[i][k] = matrix[i][j] + matrix[j][k]
                        modification = True
                    else:
                        modification = False

    return matrix

def compute(node, subset, edges):
    linked_edges = []

    for edge in edges:
        # Get only the edges linked to the node or between the node of the subset
        if edge[0] == node or edge[1] == node:
            linked_edges.append(edge)
        elif edge[0] in subset and edge[1] in subset:
            linked_edges.append(edge)

    # Generate matrix from nodes and edges
    matrix = graph_to_matrix(subset + [node], linked_edges)
    matrix = transitive_closure(matrix)

    # Make symmetrical
    for i in range(len(matrix)):
        for j in range(len(matrix)):
            if matrix[i][j] > 0:
                matrix[j][i] = matrix[i][j]

    # Compute the distance between the node and each other
    
    distances = [0 for i in range(len(subset))]
    for i in range(len(subset+1)):
        if(i == node):
            distances[i] = (0, 0)
        distances[i] = (i, matrix[node][i]) 

    # Sort the distances
    distances.sort(key=lambda x: x[1])

    # Return the sorted list of nodes
    return [x[0] for x in distances]


# In[7]:


compute(0, [1,3,4,5,7], E)

