def find_connecting_edges(infr): """ Searches for a small set of edges, which if reviewed as positive would ensure that each PCC is k-connected. Note that in somes cases this is not possible """ label = 'name_label' node_to_label = infr.get_node_attrs(label) label_to_nodes = ut.group_items(node_to_label.keys(), node_to_label.values()) # k = infr.params['redun.pos'] k = 1 new_edges = [] prog = ut.ProgIter( list(label_to_nodes.keys()), label='finding connecting edges', enabled=infr.verbose > 0, ) for nid in prog: nodes = set(label_to_nodes[nid]) G = infr.pos_graph.subgraph(nodes, dynamic=False) impossible = nxu.edges_inside(infr.neg_graph, nodes) impossible |= nxu.edges_inside(infr.incomp_graph, nodes) candidates = set(nx.complement(G).edges()) candidates.difference_update(impossible) aug_edges = nxu.k_edge_augmentation(G, k=k, avail=candidates) new_edges += aug_edges prog.ensure_newline() return new_edges
def subgraph(self, nbunch, dynamic=False): if dynamic is False: H = nx.Graph() nbunch = set(nbunch) H.add_nodes_from(nbunch) H.add_edges_from(edges_inside(self, nbunch)) else: H = super(DynConnGraph, self).subgraph(nbunch) for n in nbunch: # need to add individual nodes H._add_node(n) # Recreate the connected compoment structure for u, v in H.edges(): H._union(u, v) return H
def _cut(self, u, v): """ Decremental connectivity (slow) """ old_nid1 = self._union_find[u] old_nid2 = self._union_find[v] if old_nid1 != old_nid2: return # Need to break appart entire component and then reconstruct it old_cc = self._ccs[old_nid1] del self._ccs[old_nid1] self._union_find.remove_entire_cc(old_cc) # Might be faster to just do DFS to find the CC internal_edges = edges_inside(self, old_cc) # Add nodes in case there are no edges to it for n in old_cc: self._add_node(n) for edge in internal_edges: self._union(*edge)
def find_pos_augment_edges(infr, pcc, k=None): """ # [[1, 0], [0, 2], [1, 2], [3, 1]] pos_sub = nx.Graph([[0, 1], [1, 2], [0, 2], [1, 3]]) """ if k is None: pos_k = infr.params['redun.pos'] else: pos_k = k pos_sub = infr.pos_graph.subgraph(pcc) # TODO: # weight by pairs most likely to be comparable # First try to augment only with unreviewed existing edges unrev_avail = list(nxu.edges_inside(infr.unreviewed_graph, pcc)) try: check_edges = list( nxu.k_edge_augmentation( pos_sub, k=pos_k, avail=unrev_avail, partial=False ) ) except nx.NetworkXUnfeasible: check_edges = None if not check_edges: # Allow new edges to be introduced full_sub = infr.graph.subgraph(pcc).copy() new_avail = ut.estarmap(infr.e_, nx.complement(full_sub).edges()) full_avail = unrev_avail + new_avail n_max = (len(pos_sub) * (len(pos_sub) - 1)) // 2 n_complement = n_max - pos_sub.number_of_edges() if len(full_avail) == n_complement: # can use the faster algorithm check_edges = list( nxu.k_edge_augmentation(pos_sub, k=pos_k, partial=True) ) else: # have to use the slow approximate algo check_edges = list( nxu.k_edge_augmentation( pos_sub, k=pos_k, avail=full_avail, partial=True ) ) check_edges = set(it.starmap(e_, check_edges)) return check_edges
def find_mst_edges(infr, label='name_label'): """ Returns edges to augment existing PCCs (by label) in order to ensure they are connected with positive edges. CommandLine: python -m wbia.algo.graph.mixin_helpers find_mst_edges --profile Example: >>> # ENABLE_DOCTEST >>> from wbia.algo.graph.mixin_helpers import * # NOQA >>> import wbia >>> ibs = wbia.opendb(defaultdb='PZ_MTEST') >>> infr = wbia.AnnotInference(ibs, 'all', autoinit=True) >>> label = 'orig_name_label' >>> label = 'name_label' >>> infr.find_mst_edges() >>> infr.ensure_mst() Ignore: old_mst_edges = [ e for e, d in infr.edges(data=True) if d.get('user_id', None) == 'algo:mst' ] infr.graph.remove_edges_from(old_mst_edges) infr.pos_graph.remove_edges_from(old_mst_edges) infr.neg_graph.remove_edges_from(old_mst_edges) infr.incomp_graph.remove_edges_from(old_mst_edges) """ # Find clusters by labels node_to_label = infr.get_node_attrs(label) label_to_nodes = ut.group_items(node_to_label.keys(), node_to_label.values()) weight_heuristic = infr.ibs is not None if weight_heuristic: annots = infr.ibs.annots(infr.aids) node_to_time = ut.dzip(annots, annots.time) node_to_view = ut.dzip(annots, annots.viewpoint_code) enabled_heuristics = { 'view_weight', 'time_weight', } def _heuristic_weighting(nodes, avail_uv): avail_uv = np.array(avail_uv) weights = np.ones(len(avail_uv)) if 'view_weight' in enabled_heuristics: from vtool import _rhomb_dist view_edge = [(node_to_view[u], node_to_view[v]) for (u, v) in avail_uv] view_weight = np.array( [_rhomb_dist.VIEW_CODE_DIST[(v1, v2)] for (v1, v2) in view_edge] ) # Assume comparable by default and prefer undefined # more than probably not, but less than definately so. view_weight[np.isnan(view_weight)] = 1.5 # Prefer viewpoint 10x more than time weights += 10 * view_weight if 'time_weight' in enabled_heuristics: # Prefer linking annotations closer in time times = ut.take(node_to_time, nodes) maxtime = vt.safe_max(times, fill=1, nans=False) mintime = vt.safe_min(times, fill=0, nans=False) time_denom = maxtime - mintime # Try linking by time for lynx data time_delta = np.array( [abs(node_to_time[u] - node_to_time[v]) for u, v in avail_uv] ) time_weight = time_delta / time_denom weights += time_weight weights = np.array(weights) weights[np.isnan(weights)] = 1.0 avail = [(u, v, {'weight': w}) for (u, v), w in zip(avail_uv, weights)] return avail new_edges = [] prog = ut.ProgIter( list(label_to_nodes.keys()), label='finding mst edges', enabled=infr.verbose > 0, ) for nid in prog: nodes = set(label_to_nodes[nid]) if len(nodes) == 1: continue # We want to make this CC connected pos_sub = infr.pos_graph.subgraph(nodes, dynamic=False) impossible = set( it.starmap( e_, it.chain( nxu.edges_inside(infr.neg_graph, nodes), nxu.edges_inside(infr.incomp_graph, nodes), # nxu.edges_inside(infr.unknown_graph, nodes), ), ) ) if len(impossible) == 0 and not weight_heuristic: # Simple mst augmentation aug_edges = list(nxu.k_edge_augmentation(pos_sub, k=1)) else: complement = it.starmap(e_, nxu.complement_edges(pos_sub)) avail_uv = [(u, v) for u, v in complement if (u, v) not in impossible] if weight_heuristic: # Can do heuristic weighting to improve the MST avail = _heuristic_weighting(nodes, avail_uv) else: avail = avail_uv # logger.info(len(pos_sub)) try: aug_edges = list(nxu.k_edge_augmentation(pos_sub, k=1, avail=avail)) except nx.NetworkXUnfeasible: logger.info('Warning: MST augmentation is not feasible') logger.info('explicit negative edges might disconnect a PCC') aug_edges = list( nxu.k_edge_augmentation(pos_sub, k=1, avail=avail, partial=True) ) new_edges.extend(aug_edges) prog.ensure_newline() for edge in new_edges: assert not infr.graph.has_edge(*edge), 'alrady have edge={}'.format(edge) return new_edges
def remove_internal_priority(infr, cc): if infr.queue is not None: infr._remove_edge_priority(nxu.edges_inside(infr.graph, cc))
def reinstate_internal_priority(infr, cc): if infr.queue is not None: # Reinstate the appropriate edges into the queue edges = nxu.edges_inside(infr.unreviewed_graph, cc) infr._reinstate_edge_priority(edges)