/// <summary> /// Perform random matching partitioning. /// Input graph must be weighted on nodes. /// Nodes are only matched if they share an edge. /// </summary> /// <param name="graph">Graph with weighted nodes.</param> /// <param name="maxWeight">Maximum weight a matched pair is allowed to have.</param> /// <returns>A random matching of the nodes of the graph.</returns> public static Dictionary <int, int> RandomMatching(MultiDirectedGraph <int, int> graph, int maxWeight) { int counter = 0; var matches = new Dictionary <int, int>(); // Visit nodes randomly var nodes = graph.Nodes.ToArray(); nodes.Shuffle(); foreach (var u in nodes) { if (!matches.ContainsKey(u)) { // Node u in unmatched, match it with one of the unmatched neighbors var unmatchedNeighbors = graph.Neighbors(u).Where(v => !u.Equals(v) && !matches.ContainsKey(v) && graph.NodeLabel(u) + graph.NodeLabel(v) <= maxWeight).ToArray(); // Only match if such a neighbor exists if (unmatchedNeighbors.Length > 0) { var v = Utils.Shuffled(unmatchedNeighbors).First(); matches.Add(u, counter); matches.Add(v, counter); } else { matches.Add(u, counter); } counter += 1; } } return(matches); }
/// <summary> /// Splits the nodes of a graph into P blocks by exploring. /// </summary> /// <typeparam name="TNode">Type of node.</typeparam> /// <typeparam name="TLabel">Type of label.</typeparam> /// <param name="graph">Graph to partition the nodes of.</param> /// <param name="P">Number of partition blocks.</param> public static Dictionary <TNode, int> ExploreSplit <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, int P) { int n = graph.NumNodes; // Bucket size int B = (n + P - 1) / P; var V = new HashSet <TNode>(); var Q = new AiroQueue <TNode>(); var nodes = graph.Nodes.ToArray(); Utils.Shuffle(nodes); int seedIndex = 0; var partition = new Dictionary <TNode, int>(); Action <TNode> bucketize = node => { partition.Add(node, (n - 1) / B); }; // Walk while we need to add nodes while (n > 0) { if (Q.Count <= 0) { // Find next seed node, from an undiscovered connected component, and resume from there while (V.Contains(nodes[seedIndex])) { seedIndex += 1; } var seed = nodes[seedIndex]; // Add seed to queue and set of nodes Q.Put(seed); V.Add(seed); bucketize(seed); n -= 1; } var u = Q.Take(); var N = graph.Neighbors(u); foreach (var v in N) { if (!V.Contains(v) && n > 0) { Q.Put(v); V.Add(v); bucketize(v); n -= 1; } } } return(partition); }