150 lines
4.6 KiB
Python
150 lines
4.6 KiB
Python
#!/usr/bin/python3
|
|
from random import randint, random
|
|
import networkx as nx
|
|
import sys
|
|
|
|
class Node(object):
|
|
|
|
def __init__(self, id, g):
|
|
self.graph = g
|
|
self.id = id
|
|
self.color = None
|
|
self.candidate_list = None
|
|
self.queue = "start"
|
|
self.next_tick = None
|
|
self.edges = []
|
|
self.done = False
|
|
|
|
def add_edge(self, node):
|
|
self.edges.append(node)
|
|
|
|
def print(self):
|
|
print(f"Node {self.id} = (c:{self.color}, #e:{len(self.edges)})")
|
|
|
|
def run_tick(self):
|
|
if not self.done:
|
|
# candidate list of colors
|
|
self.candidate_list = self.graph.possible_colors.copy()
|
|
if not self.next_tick == "start":
|
|
# if its not the first iteration w/o data, filter out all neighbor colors from candidate list
|
|
neighbor_candidates = self.next_tick.copy()
|
|
for colore in neighbor_candidates:
|
|
if colore in self.candidate_list:
|
|
self.candidate_list.remove(colore)
|
|
|
|
# if color is in candidate list (no neighbors has this color), finish.
|
|
# do not run this at start
|
|
if self.color in self.candidate_list and self.color is not None:
|
|
self.done = True
|
|
self.queue = "stop"
|
|
#print(f"{self.id} | is done")
|
|
return
|
|
|
|
# pick random color from candidate list
|
|
self.color = self.candidate_list[randint(0, len(self.candidate_list) - 1)]
|
|
|
|
#print(f"{self.id} | possible colors: {self.candidate_list}, current color: {self.color}")
|
|
|
|
# send data to the other neighbors
|
|
for n in self.edges:
|
|
if n.queue != "stop":
|
|
n.queue.append(self.color)
|
|
#print(f"{self.id} => sending {self.color} to N[{n.id}]")
|
|
|
|
|
|
class Graph(object):
|
|
|
|
def __init__(self):
|
|
self.V = None
|
|
self.max_degree = None
|
|
|
|
def load_graph_file(self, graph_file):
|
|
with open(graph_file, "r") as f:
|
|
V_amt, E_amt = map(int, f.readline().split(" "))
|
|
self.V = [Node(x, self) for x in range(1, V_amt+1)]
|
|
self.E = {}
|
|
self.max_degree = 0
|
|
for i in range(0, E_amt):
|
|
a, b = map(int, f.readline().split(" "))
|
|
a -= 1
|
|
b -= 1
|
|
self.V[a].add_edge(self.V[b])
|
|
self.V[b].add_edge(self.V[a])
|
|
self.max_degree = max(self.max_degree, len(self.V[a].edges), len(self.V[b].edges))
|
|
|
|
self.possible_colors = [x for x in range(1, self.max_degree + 2)]
|
|
|
|
def load_graph_networkx(self, graph):
|
|
self.V = [Node(x, self) for x in range(1, graph.number_of_nodes() + 1)]
|
|
self.E = {}
|
|
self.max_degree = 0
|
|
for a, b in graph.edges:
|
|
self.V[a].add_edge(self.V[b])
|
|
self.V[b].add_edge(self.V[a])
|
|
self.max_degree = max(self.max_degree, len(self.V[a].edges), len(self.V[b].edges))
|
|
|
|
self.possible_colors = [x for x in range(1, self.max_degree + 2)]
|
|
|
|
def run_tick(self):
|
|
print("Next Tick")
|
|
# send data
|
|
for n in self.V:
|
|
n.next_tick = n.queue
|
|
n.queue = []
|
|
# run tick for each
|
|
for n in self.V:
|
|
n.run_tick()
|
|
|
|
done = True
|
|
for n in self.V:
|
|
done &= n.done
|
|
|
|
if done:
|
|
print("Stop")
|
|
return -1
|
|
pass
|
|
|
|
def print_graph(self):
|
|
print(f"Max Degree: {self.max_degree}")
|
|
for n in self.V:
|
|
n.print()
|
|
|
|
def check_correctness(self):
|
|
for n in self.V:
|
|
color = n.color
|
|
for neighbor in n.edges:
|
|
if neighbor.color == color:
|
|
print("=====================")
|
|
n.print()
|
|
neighbor.print()
|
|
print(f"Neighbor {neighbor.id} has same color as {n.id}")
|
|
print("=====================")
|
|
return False
|
|
return True
|
|
|
|
def main():
|
|
g = Graph()
|
|
if len(sys.argv) == 2:
|
|
filename = sys.argv[1]
|
|
g.load_graph(filename)
|
|
else:
|
|
G = nx.erdos_renyi_graph(randint(100, 300), random())
|
|
g.load_graph_networkx(G)
|
|
|
|
g.print_graph()
|
|
|
|
for i in range(0, 10):
|
|
ret = g.run_tick()
|
|
if ret == -1:
|
|
# print info
|
|
print("Final colors:")
|
|
for n in g.V:
|
|
n.print()
|
|
|
|
# assert if correct
|
|
assert g.check_correctness()
|
|
exit(0)
|
|
pass
|
|
|
|
if __name__ == '__main__':
|
|
main() |