/// <summary> /// Marks the minimum spanning arborescence of a plan graph by setting the IncomingMSAEdge /// fields for all nodes /// </summary> /// <param name="planGraph">The plan graph to be marked</param> /// <param name="dumpName">Names the dump targets if dump compiler flags are set</param> public void MarkMinimumSpanningArborescence(PlanGraph planGraph, String dumpName) { if(DumpSearchPlan) DumpPlanGraph(planGraph, dumpName, "initial"); // nodes not already looked at Dictionary<PlanNode, bool> leftNodes = new Dictionary<PlanNode, bool>(planGraph.Nodes.Length); foreach(PlanNode node in planGraph.Nodes) leftNodes.Add(node, true); // epoch = search run Dictionary<PlanPseudoNode, bool> epoch = new Dictionary<PlanPseudoNode, bool>(); LinkedList<PlanSuperNode> superNodeStack = new LinkedList<PlanSuperNode>(); // work left ? while(leftNodes.Count > 0) { // get first remaining node Dictionary<PlanNode, bool>.Enumerator enumerator = leftNodes.GetEnumerator(); enumerator.MoveNext(); PlanPseudoNode curNode = enumerator.Current.Key; // start a new search run epoch.Clear(); do { // next node in search run epoch.Add(curNode, true); if(curNode is PlanNode) leftNodes.Remove((PlanNode) curNode); // cheapest incoming edge of current node float cost; PlanEdge cheapestEdge = curNode.GetCheapestIncoming(curNode, out cost); if(cheapestEdge == null) break; curNode.IncomingMSAEdge = cheapestEdge; // cycle found ? while(epoch.ContainsKey(cheapestEdge.Source.TopNode)) { // contract the cycle to a super node PlanSuperNode superNode = new PlanSuperNode(cheapestEdge.Source.TopNode); superNodeStack.AddFirst(superNode); epoch.Add(superNode, true); if(superNode.IncomingMSAEdge == null) goto exitSecondLoop; // continue with new super node as current node curNode = superNode; cheapestEdge = curNode.IncomingMSAEdge; } curNode = cheapestEdge.Source.TopNode; } while(true); exitSecondLoop: ; } if(DumpSearchPlan) { DumpPlanGraph(planGraph, dumpName, "contracted"); DumpContractedPlanGraph(planGraph, dumpName); } // breaks all cycles represented by setting the incoming msa edges of the // representative nodes to the incoming msa edges according to the supernode /*no, not equivalent: foreach(PlanSuperNode superNode in superNodeStack) superNode.Child.IncomingMSAEdge = superNode.IncomingMSAEdge;*/ foreach (PlanSuperNode superNode in superNodeStack) { PlanPseudoNode curNode = superNode.IncomingMSAEdge.Target; while (curNode.SuperNode != superNode) curNode = curNode.SuperNode; curNode.IncomingMSAEdge = superNode.IncomingMSAEdge; if(curNode.IncomingMSAEdge == null) throw new Exception(); } if(DumpSearchPlan) DumpFinalPlanGraph(planGraph, dumpName); }
private void DumpSuperNode(StreamWriter sw, PlanSuperNode superNode, Dictionary<PlanSuperNode, bool> dumpedSuperNodes) { PlanPseudoNode curNode = superNode.Child; sw.WriteLine("graph:{title:\"super node\" label:\"super node\" status:clustered color:lightgrey"); dumpedSuperNodes.Add(superNode, true); do { if(curNode is PlanSuperNode) { DumpSuperNode(sw, (PlanSuperNode) curNode, dumpedSuperNodes); DumpEdge(sw, curNode.IncomingMSAEdge, true); } else { DumpNode(sw, (PlanNode) curNode); DumpEdge(sw, curNode.IncomingMSAEdge, false); } curNode = curNode.IncomingMSAEdge.Source; while(curNode.SuperNode != null && curNode.SuperNode != superNode) curNode = curNode.SuperNode; } while(curNode != superNode.Child); sw.WriteLine("}"); }