public void MinCutTest() { Graph <BasicEdgeNode, BasicEdge> g = new Graph <BasicEdgeNode, BasicEdge>(BasicEdge.New); // this graph is from Cormen et al, fig 27.1 BasicEdgeNode s = new BasicEdgeNode("s"); BasicEdgeNode v1 = new BasicEdgeNode("v1"); BasicEdgeNode v2 = new BasicEdgeNode("v2"); BasicEdgeNode v3 = new BasicEdgeNode("v3"); BasicEdgeNode v4 = new BasicEdgeNode("v4"); BasicEdgeNode t = new BasicEdgeNode("t"); g.Nodes.Add(s); g.Nodes.Add(v1); g.Nodes.Add(v2); g.Nodes.Add(v3); g.Nodes.Add(v4); g.Nodes.Add(t); Dictionary <BasicEdge, float> capacity = new Dictionary <BasicEdge, float>(); BasicEdge e; e = g.AddEdge(s, v1); capacity[e] = 16; e = g.AddEdge(s, v2); capacity[e] = 13; e = g.AddEdge(v1, v2); capacity[e] = 10; e = g.AddEdge(v1, v3); capacity[e] = 12; e = g.AddEdge(v2, v1); capacity[e] = 4; e = g.AddEdge(v2, v4); capacity[e] = 14; e = g.AddEdge(v3, v2); capacity[e] = 9; e = g.AddEdge(v3, t); capacity[e] = 20; e = g.AddEdge(v4, v3); capacity[e] = 7; e = g.AddEdge(v4, t); capacity[e] = 4; var mc = new MinCut <BasicEdgeNode, BasicEdge>(g, e2 => capacity[e2]); mc.Sources.Add(s); mc.Sinks.Add(t); // sourceGroup should be s,v1,v2,v4 Set <BasicEdgeNode> sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); Assert.True(sourceGroup.Count == 4 && sourceGroup.ContainsAll(new BasicEdgeNode[] { s, v1, v2, v4 })); mc.Sources.Add(v1); mc.Sinks.Add(v3); sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); Assert.True(sourceGroup.Count == 4 && sourceGroup.ContainsAll(new BasicEdgeNode[] { s, v1, v2, v4 })); capacity[g.GetEdge(v2, v4)] = 1; sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); Assert.True(sourceGroup.Count == 3 && sourceGroup.ContainsAll(new BasicEdgeNode[] { s, v1, v2 })); }
public void MinCutCycleTest() { Graph <BasicEdgeNode, BasicEdge> g = new Graph <BasicEdgeNode, BasicEdge>(BasicEdge.New); // cycle graph BasicEdgeNode s = new BasicEdgeNode("s"); BasicEdgeNode v1 = new BasicEdgeNode("v1"); BasicEdgeNode v2 = new BasicEdgeNode("v2"); BasicEdgeNode t = new BasicEdgeNode("t"); g.Nodes.Add(s); g.Nodes.Add(v1); g.Nodes.Add(v2); g.Nodes.Add(t); Dictionary <BasicEdge, float> capacity = new Dictionary <BasicEdge, float>(); BasicEdge e; e = g.AddEdge(s, v1); capacity[e] = 16; e = g.AddEdge(v1, v2); capacity[e] = 10; e = g.AddEdge(v2, s); capacity[e] = 14; var mc = new MinCut <BasicEdgeNode, BasicEdge>(g, e2 => capacity[e2]); mc.Sources.Add(s); mc.Sinks.Add(s); // sourceGroup should be s,v1 Set <BasicEdgeNode> sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); Assert.True(sourceGroup.Count == 2 && sourceGroup.ContainsAll(new BasicEdgeNode[] { s, v1 })); mc.Sinks.Remove(s); // test the case where t is not reachable from s mc.Sinks.Add(t); // sourceGroup should be s,v1,v2 sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); Assert.True(sourceGroup.Count == 3 && sourceGroup.ContainsAll(new BasicEdgeNode[] { s, v1, v2 })); // test IsSinkEdge mc.Sinks.Remove(t); e = g.GetEdge(v2, s); mc.IsSinkEdge = edge => edge.Equals(e); // sourceGroup should be s,v1 sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); Assert.True(sourceGroup.Count == 2 && sourceGroup.ContainsAll(new BasicEdgeNode[] { s, v1 })); }
/// <summary> /// Test of solving an initializer scheduling problem as a min cut problem. /// </summary> //[Fact] internal void MinCutTest3() { Graph <BasicEdgeNode, BasicEdge> g = new Graph <BasicEdgeNode, BasicEdge>(BasicEdge.New); BasicEdgeNode s = new BasicEdgeNode("s"); BasicEdgeNode v1 = new BasicEdgeNode("v1"); BasicEdgeNode v2 = new BasicEdgeNode("v2"); BasicEdgeNode v3 = new BasicEdgeNode("v3"); BasicEdgeNode b1 = new BasicEdgeNode("b1"); BasicEdgeNode b2 = new BasicEdgeNode("b2"); BasicEdgeNode t = new BasicEdgeNode("t"); g.Nodes.Add(s); g.Nodes.Add(v1); g.Nodes.Add(v2); g.Nodes.Add(v3); g.Nodes.Add(b1); g.Nodes.Add(b2); g.Nodes.Add(t); Dictionary <BasicEdge, float> capacity = new Dictionary <BasicEdge, float>(); foreach (var node in new[] { v1, v2, v3 }) { BasicEdge e2 = g.AddEdge(s, node); capacity[e2] = 1; } BasicEdgeNode[,] pairs = { { v1, b1 }, { v2, b1 }, { v2, b2 }, { v3, b2 } }; for (int i = 0; i < pairs.GetLength(0); i++) { var source = pairs[i, 0]; var target = pairs[i, 1]; BasicEdge e2 = g.AddEdge(source, target); capacity[e2] = 1; } BasicEdge e; e = g.AddEdge(b1, t); capacity[e] = 1.1f; e = g.AddEdge(b2, t); capacity[e] = 1.1f; var mc = new MinCut <BasicEdgeNode, BasicEdge>(g, e2 => capacity[e2]); mc.Sources.Add(s); mc.Sinks.Add(t); Set <BasicEdgeNode> sourceGroup = mc.GetSourceGroup(); Console.WriteLine("sourceGroup = {0}", sourceGroup); }
protected override void DoConvertMethodBody(IList <IStatement> outputs, IList <IStatement> inputs) { List <int> whileNumberOfNode = new List <int>(); List <int> fusedCountOfNode = new List <int>(); List <List <IStatement> > containersOfNode = new List <List <IStatement> >(); // the code may have multiple while(true) loops, however these must be disjoint. // therefore we treat 'while' as one container, but give each loop a different 'while number'. int outerWhileCount = 0; int currentOuterWhileNumber = 0; int currentFusedCount = 0; List <Set <IVariableDeclaration> > loopVarsOfWhileNumber = new List <Set <IVariableDeclaration> >(); // build the dependency graph var g = new DependencyGraph2(context, inputs, DependencyGraph2.BackEdgeHandling.Ignore, delegate(IWhileStatement iws) { if (iws is IFusedBlockStatement) { if (iws.Condition is IVariableReferenceExpression) { currentFusedCount++; } } else { outerWhileCount++; currentOuterWhileNumber = outerWhileCount; } }, delegate(IWhileStatement iws) { if (iws is IFusedBlockStatement) { if (iws.Condition is IVariableReferenceExpression) { currentFusedCount--; } } else { currentOuterWhileNumber = 0; } }, delegate(IConditionStatement ics) { }, delegate(IConditionStatement ics) { }, delegate(IStatement ist, int targetIndex) { int whileNumber = currentOuterWhileNumber; whileNumberOfNode.Add(whileNumber); fusedCountOfNode.Add(currentFusedCount); List <IStatement> containers = new List <IStatement>(); LoopMergingTransform.UnwrapStatement(ist, containers); containersOfNode.Add(containers); for (int i = 0; i < currentFusedCount; i++) { if (containers[i] is IForStatement ifs) { var loopVar = Recognizer.LoopVariable(ifs); if (loopVarsOfWhileNumber.Count <= whileNumber) { while (loopVarsOfWhileNumber.Count <= whileNumber) { loopVarsOfWhileNumber.Add(new Set <IVariableDeclaration>()); } } Set <IVariableDeclaration> loopVars = loopVarsOfWhileNumber[whileNumber]; loopVars.Add(loopVar); } } }); var nodes = g.nodes; var dependencyGraph = g.dependencyGraph; for (int whileNumber = 1; whileNumber < loopVarsOfWhileNumber.Count; whileNumber++) { foreach (var loopVar in loopVarsOfWhileNumber[whileNumber]) { // Any statement (in the while loop) that has a forward descendant and a backward descendant will be cloned, so we want to minimize the number of such nodes. // The free variables in this problem are the loop directions at the leaf statements, since all other loop directions are forced by these. // We find the optimal labeling of the free variables by solving a min cut problem on a special network. // The network is constructed so that the cost of a cut is equal to the number of statements that will be cloned. // The network has 2 nodes for every statement: an in-node and an out-node. // For a non-leaf statement, there is a capacity 1 edge from the in-node to out-node. This edge is cut when the statement is cloned. // For a leaf statement, there is an infinite capacity edge in both directions, or equivalently a single node. // If statement A depends on statement B, then there is an infinite capacity edge from in-A to in-B, and from out-B to out-A, // representing the fact that cloning A requires cloning B, but not the reverse. // If a statement must appear with a forward loop, it is connected to the source. // If a statement must appear with a backward loop, it is connected to the sink. // construct a capacitated graph int inNodeStart = 0; int outNodeStart = inNodeStart + dependencyGraph.Nodes.Count; int sourceNode = outNodeStart + dependencyGraph.Nodes.Count; int sinkNode = sourceNode + 1; int cutNodeCount = sinkNode + 1; Func <NodeIndex, int> getInNode = node => node + inNodeStart; Func <NodeIndex, int> getOutNode = node => node + outNodeStart; IndexedGraph network = new IndexedGraph(cutNodeCount); const float infinity = 1000000f; List <float> capacity = new List <float>(); List <NodeIndex> nodesOfInterest = new List <NodeIndex>(); foreach (var node in dependencyGraph.Nodes) { if (whileNumberOfNode[node] != whileNumber) { continue; } NodeIndex source = node; List <IStatement> containersOfSource = containersOfNode[source]; bool hasLoopVar = containersOfSource.Any(container => container is IForStatement && Recognizer.LoopVariable((IForStatement)container) == loopVar); if (!hasLoopVar) { continue; } nodesOfInterest.Add(node); IStatement sourceSt = nodes[source]; var readAfterWriteEdges = dependencyGraph.EdgesOutOf(source).Where(edge => !g.isWriteAfterRead[edge]); bool isLeaf = true; int inNode = getInNode(node); int outNode = getOutNode(node); foreach (var target in readAfterWriteEdges.Select(dependencyGraph.TargetOf)) { List <IStatement> containersOfTarget = containersOfNode[target]; IStatement targetSt = nodes[target]; ForEachMatchingLoopVariable(containersOfSource, containersOfTarget, (loopVar2, afs, bfs) => { if (loopVar2 == loopVar) { int inTarget = getInNode(target); int outTarget = getOutNode(target); network.AddEdge(inTarget, inNode); capacity.Add(infinity); network.AddEdge(outNode, outTarget); capacity.Add(infinity); isLeaf = false; } }); } if (isLeaf) { if (debug) { log.Add($"loopVar={loopVar.Name} leaf {sourceSt}"); } network.AddEdge(inNode, outNode); capacity.Add(infinity); network.AddEdge(outNode, inNode); capacity.Add(infinity); } else { network.AddEdge(inNode, outNode); capacity.Add(1f); } int fusedCount = fusedCountOfNode[node]; Direction desiredDirectionOfSource = GetDesiredDirection(loopVar, containersOfSource, fusedCount); if (desiredDirectionOfSource == Direction.Forward) { if (debug) { log.Add($"loopVar={loopVar.Name} forward {sourceSt}"); } network.AddEdge(sourceNode, inNode); capacity.Add(infinity); } else if (desiredDirectionOfSource == Direction.Backward) { if (debug) { log.Add($"loopVar={loopVar.Name} backward {sourceSt}"); } network.AddEdge(outNode, sinkNode); capacity.Add(infinity); } } network.IsReadOnly = true; // compute the min cut MinCut <NodeIndex, EdgeIndex> mc = new MinCut <EdgeIndex, EdgeIndex>(network, e => capacity[e]); mc.Sources.Add(sourceNode); mc.Sinks.Add(sinkNode); Set <NodeIndex> sourceGroup = mc.GetSourceGroup(); foreach (NodeIndex node in nodesOfInterest) { IStatement sourceSt = nodes[node]; bool forwardIn = sourceGroup.Contains(getInNode(node)); bool forwardOut = sourceGroup.Contains(getOutNode(node)); if (forwardIn != forwardOut) { if (debug) { log.Add($"loopVar={loopVar.Name} will clone {sourceSt}"); } } else if (forwardIn) { if (debug) { log.Add($"loopVar={loopVar.Name} wants forward {sourceSt}"); } } else { if (debug) { log.Add($"loopVar={loopVar.Name} wants backward {sourceSt}"); } var containers = containersOfNode[node]; bool isForwardLoop = true; foreach (var container in containers) { if (container is IForStatement) { IForStatement ifs = (IForStatement)container; if (Recognizer.LoopVariable(ifs) == loopVar) { isForwardLoop = Recognizer.IsForwardLoop(ifs); } } } if (isForwardLoop) { Set <IVariableDeclaration> loopVarsToReverse; if (!loopVarsToReverseInStatement.TryGetValue(sourceSt, out loopVarsToReverse)) { // TODO: re-use equivalent sets loopVarsToReverse = new Set <IVariableDeclaration>(); loopVarsToReverseInStatement.Add(sourceSt, loopVarsToReverse); } loopVarsToReverse.Add(loopVar); } } } } } base.DoConvertMethodBody(outputs, inputs); }