def clustering(agraph, k): """ Max-Spacing k clustering Return maximum spacing of a k-clustering and corresponding mst. """ # minimum spanning tree mst = [] # disjoint set disjoint_set = DisjointSet() # make set for vertex in agraph.Vertices(): disjoint_set.make_set(vertex) # edges of the graph edges = agraph.edges() edges.sort(key=lambda tup: tup[2]) for u, v, cost in edges: if len(disjoint_set) >= k: if disjoint_set.find_set(u) != disjoint_set.find_set(v): mst.append((u, v, cost)) max_cost = cost disjoint_set.union(u, v) else: break return max_cost, mst
def kruskal_minimum_spanning_tree(graph: Graph) -> list[Edge]: """Return list of edges, representing minimum spanning tree""" vertices = get_all_nodes(graph) edges = get_all_edges(graph) djs = DisjointSet(vertices) sorted_edges = sorted(edges, key=lambda edge: edge.weight) res: list[Edge] = [] for edge in sorted_edges: if djs.find_set(edge.u) != djs.find_set(edge.v): res.append(edge) djs.union_sets(edge.u, edge.v) return res
def kruskal(graph: DisjointSet, edges): ''' Keep edges as a list with (source: disjoint_set node, destination: disjoint_set node, weight) as items and graph is the DisjointSet ''' s_edges = sorted(edges, key=itemgetter(2)) tree = list() for u, v, w in s_edges: if graph.find_set(u) is not graph.find_set(v): tree.append((u, v, w)) graph.union(u, v) return tree
def kruskal_mst(agraph): """ Return a minimum spanning tree using kruskal's algorithm """ # minimum spanning tree mst = [] # disjoint set disjoint_set = DisjointSet() # make set for vertex in agraph.Vertices(): disjoint_set.make_set(vertex) # edges of the graph edges = agraph.edges() edges.sort(key=lambda tup: tup[2]) for u, v, cost in edges: if disjoint_set.find_set(u) != disjoint_set.find_set(v): mst.append((u, v, cost)) disjoint_set.union(u, v) return mst
def minimize(self): self._remove_unreachable_states() def order_tuple(a, b): return (a, b) if a < b else (b, a) table = {} sorted_states = sorted(self.states) # initialize the table for i, item in enumerate(sorted_states): for item_2 in sorted_states[i + 1:]: table[(item, item_2)] = (item in self.final_states) != (item_2 \ in self.final_states) flag = True # table filling method while flag: flag = False for i, item in enumerate(sorted_states): for item_2 in sorted_states[i + 1:]: if table[(item, item_2)]: continue # check if the states are distinguishable for w in self.terminals: t1 = self.transitions.get((item, w), None) t2 = self.transitions.get((item_2, w), None) if t1 is not None and t2 is not None and t1 != t2: marked = table[order_tuple(t1, t2)] flag = flag or marked table[(item, item_2)] = marked if marked: break d = DisjointSet(self.states) # form new states for k, v in table.items(): if not v: d.union(k[0], k[1]) self.states = [str(x) for x in range(1, 1 + len(d.get()))] new_final_states = [] self.start_state = str(d.find_set(self.start_state)) for s in d.get(): for item in s: if item in self.final_states: new_final_states.append(str(d.find_set(item))) break self.transitions = {(str(d.find_set(k[0])), k[1]): str(d.find_set(v)) for k, v in self.transitions.items()} self.final_states = new_final_states
def minimize(self): # Removendo os estados inatingíveis self._remove_unreachable_states() # Manter a ordem dos elementos na tuplas será importante # para saber quais "quadrados" já foram marcados na tabela def order_tuple(a, b): return (a, b) if a < b else (b, a) # Usaremos o algoritmo da tabela visto em aula para marcar # os estados que são distintos table = {} # Ordenamos os estados para que possamos fazer tudo em sequência, # do primeiro até o último estado sorted_states = sorted(self.states) # Inicializando a tabela marcando todos os quadrados onde # temos um estado final e um estado não final, que são, trivialmente # distintos for i, item in enumerate(sorted_states): for item_2 in sorted_states[i + 1:]: table[(item, item_2)] = (item in self.final_states) != ( item_2 in self.final_states) flag = True # Preenchendo o resto da tabela while flag: flag = False # Vamos olhar para as cobinações de estados da seguinte maneira # Pegamos um estado qi, com 0 <= i < n (n = quantidade de estados), com qj, com i < j < n. for i, item in enumerate(sorted_states): for item_2 in sorted_states[i + 1:]: # Verificamos se o quadrado já está marcado if table[(item, item_2)]: # Se estiver, então os estados são distintos continue # Precisamos checar as transições dos estado item e item_2 # para saber se eles são distinguíveis for w in self.terminals: # 'None' é para o caso em que algum estado não esteja # definido para algum determinado terminal t1 = self.transitions.get((item, w), None) t2 = self.transitions.get((item_2, w), None) if t1 is not None and t2 is not None and t1 != t2: # Se para pelo menos um transição os estados forem # distintos, então os marcamos na tabela marked = table[order_tuple(t1, t2)] flag = flag or marked # Se os estads t1 e t2 forem distintos, então os # estados item e item_2 também serão distintos # então, ao invés de criar uma lista de dependências, # já vamos logo marcando (item,item_2) como sendo distintos table[(item, item_2)] = marked if marked: break d = DisjointSet(self.states) # Após analisar os estados, e descobrir aqueles que são distintos # e aqueles que não são, unimos aqueles que são iguais num único estado for k, v in table.items(): if not v: d.union(k[0], k[1]) # Atualizando os estados após a união dos estados iguais # d.get() retorna o conjunto com os arrays # de estados, se o array tem um único elemento # então não há estados equivalentes ao estado # em questão, se houver dois ou mais estados # no mesmo array, então todos aqueles estados são # equivalentes self.states = [str(x) for x in range(1, 1 + len(d.get()))] new_final_states = [] # Buscando no disjoint set o array onde # está o estado inicial self.start_state = str(d.find_set(self.start_state)) # Pegando os arrays de estados do 'd' for s in d.get(): # Pegando os estados de 's' for item in s: if item in self.final_states: # Construindo uma lista de novos estados finais new_final_states.append(str(d.find_set(item))) break # Atualizando as transições self.transitions = {(str(d.find_set(k[0])), k[1]): str(d.find_set(v)) for k, v in self.transitions.items()} self.final_states = new_final_states print("AFD minimizado")