From 34b7a83d1ac6eb4b54a9e09ec432bb480ec59dd5 Mon Sep 17 00:00:00 2001 From: Andreas Fruhwirt Date: Wed, 10 Jan 2024 19:48:30 +0100 Subject: [PATCH] not working yet --- Readme.md | 17 ++++++ main.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++++ test_graph.txt | 6 ++ 3 files changed, 173 insertions(+) create mode 100644 Readme.md create mode 100644 main.py create mode 100644 test_graph.txt diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..332e850 --- /dev/null +++ b/Readme.md @@ -0,0 +1,17 @@ +The goal of this exercise is to provide a centralized implementation that simulates +a randomized distributed algorithm. Your implementation should take a graph +$G = (V, E)$ with maximum degree $\Delta$ as its input and simulate the following distributed +randomized $(\Delta + 1)$-coloring algorithm until all vertices are colored: + +*Initially, all nodes are uncolored. Then, in synchronous iterations, each uncolored +node selects a random candidate color from its list of available colors, that is, from +the set of colors that none of its already permanently colored neighbors have. Then, +nodes exchange their candidate colors with their neighbors. A node v that has a +candidate color c that is not selected as a candidate color by any of its neighbors +gets permanently colored with c, otherwise v discards its candidate color, remains +uncolored, and proceeds with the next iteration.* + +The code may be written in any programming language. Submit your code via +GIT (link the repository in your submission) including instructions on how to run it. +Additionally provide several example inputs (on at least a few hundred nodes) and a +test case that your algorithm computes a proper vertex coloring. \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..d674a4e --- /dev/null +++ b/main.py @@ -0,0 +1,150 @@ +#!/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() \ No newline at end of file diff --git a/test_graph.txt b/test_graph.txt new file mode 100644 index 0000000..140d9ac --- /dev/null +++ b/test_graph.txt @@ -0,0 +1,6 @@ +6 5 +1 4 +4 3 +3 2 +2 5 +5 6 \ No newline at end of file