def _kernighan_lin_sweep(edges, side): """ This is a modified form of Kernighan-Lin, which moves single nodes at a time, alternating between sides to keep the bisection balanced. We keep two min-heaps of swap costs to make optimal-next-move selection fast. """ costs0, costs1 = costs = BinaryHeap(), BinaryHeap() for u, side_u, edges_u in zip(count(), side, edges): cost_u = sum(w if side[v] else -w for v, w in edges_u) costs[side_u].insert(u, cost_u if side_u else -cost_u) def _update_costs(costs_x, x): for y, w in edges[x]: costs_y = costs[side[y]] cost_y = costs_y.get(y) if cost_y is not None: cost_y += 2 * (-w if costs_x is costs_y else w) costs_y.insert(y, cost_y, True) i = totcost = 0 while costs0 and costs1: u, cost_u = costs0.pop() _update_costs(costs0, u) v, cost_v = costs1.pop() _update_costs(costs1, v) totcost += cost_u + cost_v yield totcost, i, (u, v)
def _kernighan_lin_sweep(edges, side): costs0, costs1 = costs = BinaryHeap(), BinaryHeap() for u, side_u, edges_u in zip(count(), side, edges): cost_u = sum(w if side[v] else -w for v, w in edges_u) costs[side_u].insert(u, cost_u if side_u else -cost_u) def _update_costs(costs_x, x): for y, w in edges[x]: costs_y = costs[side[y]] cost_y = costs_y.get(y) if cost_y is not None: cost_y += 2 * (-w if costs_x is costs_y else w) costs_y.insert(y, cost_y, True) i = totcost = 0 while costs0 and costs1: u, cost_u = costs0.pop() _update_costs(costs0, u) v, cost_v = costs1.pop() _update_costs(costs1, v) totcost += cost_u + cost_v yield totcost, i, (u, v) i += 1