def sort_dependencies(items): """Topologically sort the dependency tree""" g = DiGraph() log("Sorting dependencies") for key, item in items: log("key: ", key, "item:", item, pretty=True, lvl=debug) dependencies = item.get("dependencies", []) if isinstance(dependencies, str): dependencies = [dependencies] if key not in g: g.add_node(key) for link in dependencies: g.add_edge(key, link) if not is_directed_acyclic_graph(g): log("Cycles in provisioning dependency graph detected!", lvl=error) log("Involved provisions:", list(simple_cycles(g)), lvl=error) topology = list(topological_sort(g)) topology.reverse() topology = list(set(topology).difference(installed)) # log(topology, pretty=True) return topology
def get_stations_on_trips_in_order(trip_list): # This could easily live on the Line object dg = networkx.DiGraph() for t in trip_list: for s in t.get_segments(): s.add_as_digraph_edge(dg, ignore_lines=True) return topological_sort(dg)
def _ancestors_in_topological_sort_order(module_name): ancestral_module_names = ancestors(_dependency_graph, module_name) subgraph = _dependency_graph.subgraph(ancestral_module_names) try: sorted_nodes = topological_sort(subgraph) except nx.NetworkXUnfeasible as ex: try: cycle = find_cycle(subgraph) except Exception as ex: log_error(f'find_cycle: error: {ex.__class__.__name__}({ex})') else: log_error(f'cycle: {cycle}') finally: raise else: return list(reversed(list(sorted_nodes)))
def order_dps(name2dp, connections): """ Returns a total order consistent with the partial order """ names = set(name2dp) # List the ones that have no functions or no resources # a >= 10 g (no functions) # b <= 10 s (no resources) # # no_functions = set() # # no_resources = set() # # # # for name, ndp in name2dp.items(): # # if not ndp.get_fnames(): # # no_functions.add(name) # # if not ndp.get_rnames(): # # no_resources.add(name) # # print('no_functions: %s' % no_functions) # print('no_resources: %s' % no_resources) G = get_connection_graph(names, connections) # I should probably think more about this # for nf in no_functions: # for nr in no_resources: # G.add_edge(nr, nf) Gu = G.to_undirected() if not is_connected(Gu): msg = 'The graph is not weakly connected. (missing constraints?)' msg += '\nNames: %s' % names msg += '\nconnections: %s' % connections raise DPSemanticError(msg) l = list(topological_sort(G)) if not (set(l) == names): msg = 'names = %s\n returned = %s\n connections: %s' % (names, l, connections) msg += '\n graph: %s %s' % (list(Gu.nodes()), list(Gu.edges())) raise DPInternalError(msg) return l
def order_dps(name2dp, connections): """ Returns a total order consistent with the partial order """ names = set(name2dp) # List the ones that have no functions or no resources # a >= 10 g (no functions) # b <= 10 s (no resources) # # no_functions = set() # # no_resources = set() # # # # for name, ndp in name2dp.items(): # # if not ndp.get_fnames(): # # no_functions.add(name) # # if not ndp.get_rnames(): # # no_resources.add(name) # # print('no_functions: %s' % no_functions) # print('no_resources: %s' % no_resources) G = get_connection_graph(names, connections) # I should probably think more about this # for nf in no_functions: # for nr in no_resources: # G.add_edge(nr, nf) Gu = G.to_undirected() if not is_connected(Gu): msg = 'The graph is not weakly connected. (missing constraints?)' msg += '\nNames: %s' % names msg += '\nconnections: %s' % connections raise DPSemanticError(msg) l = topological_sort(G) if not (set(l) == names): msg = 'names = %s\n returned = %s\n connections: %s' % (names, l, connections) msg += '\n graph: %s %s' % (list(Gu.nodes()), list(Gu.edges())) raise DPInternalError(msg) return l
def nearest_drop_map( map_width, factory_loc, dropoff_locs, halite_map, halite_scale=100.0, avoidance_map=None, build_return_trees=False, ship_ind_arr=None, ): """For each tile, provide number of turns to nearest drop + halite cost / halite_scale. The Halite cost is to be used to distinguish between routes that are equally long. Use BFS. """ locs = [factory_loc] + dropoff_locs locs_copy = copy(locs) out_arr = np.full_like(halite_map, np.inf) locq = deque() if build_return_trees: import networkx # edges go from depos (root to leaf) digraph = networkx.DiGraph() for loc in locs: out_arr[loc[0], loc[1]] = 0 locq.append(((loc[0], loc[1]), None)) if build_return_trees: digraph.add_node((loc[0], loc[1])) del locs while locq: (loc, parent) = locq.popleft() if parent is not None: val = ( out_arr[parent[0], parent[1]] + 1 + int(halite_map[loc[0], loc[1]] / 10) / halite_scale ) if parent is None or (val < out_arr[loc[0], loc[1]]): if ( (avoidance_map is not None) and avoidance_map[loc[0], loc[1]] and ((loc[0], loc[1]) not in locs_copy) ): pass else: for d in [(0, 1), (1, 0), (-1, 0), (0, -1)]: new_loc = ((loc[0] + d[0]) % map_width, (loc[1] + d[1]) % map_width) locq.append((new_loc, loc)) if parent is not None: curr_val = out_arr[loc[0], loc[1]] if val < curr_val: out_arr[loc[0], loc[1]] = val if build_return_trees: digraph.add_edge((parent[0], parent[1]), (loc[0], loc[1])) else: out_arr[loc[0], loc[1]] = curr_val if not build_return_trees: return out_arr else: return_turn_arr = np.full_like(halite_map, hlt.constants.MAX_TURNS) depo_nodes = (n for n in digraph.nodes() if digraph.in_degree(n) == 0) depo_adj_nodes = [] for node in depo_nodes: successors = digraph.successors(node) for successor in successors: depo_adj_nodes.append(successor) from networkx.algorithms.traversal.depth_first_search import dfs_tree from networkx.algorithms import topological_sort for node in depo_adj_nodes: subtree = dfs_tree(digraph, node) root_out = list(topological_sort(subtree)) i = 0 for node in reversed(root_out): return_turn = hlt.constants.MAX_TURNS - i return_turn_arr[node[0], node[1]] = return_turn if ship_ind_arr[node[0], node[1]]: i += 1 return out_arr, return_turn_arr