Ejemplo n.º 1
0
 public void InheritSourceConflicts(NodeIndex newNode, NodeIndex oldNode)
 {
     foreach (EdgeIndex edge in graph.EdgesInto(oldNode).ToArray())
     {
         int       source = graph.SourceOf(edge);
         EdgeIndex edge2  = graph.AddEdge(source, newNode);
         prohibitedLoopVars[edge2] = prohibitedLoopVars[edge];
         offsetInfos[edge2]        = offsetInfos[edge];
     }
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Analyse equality constraints, which appear as static method calls to Constrain.Equal
 /// </summary>
 /// <param name="imie"></param>
 /// <returns></returns>
 protected override IExpression ConvertMethodInvoke(IMethodInvokeExpression imie)
 {
     // If this is a constrain equal, then we will add the equality to the equality map.
     if (Recognizer.IsStaticGenericMethod(imie, new Action <PlaceHolder, PlaceHolder>(Constrain.Equal <PlaceHolder>)))
     {
         int node0 = CreateNodeAndEdges(imie.Arguments[0]);
         int node1 = CreateNodeAndEdges(imie.Arguments[1]);
         graph.AddEdge(node0, node1);
         graph.AddEdge(node1, node0);
     }
     return(base.ConvertMethodInvoke(imie));
 }
Ejemplo n.º 3
0
        public void IndexedGraphTest()
        {
            IndexedGraph g   = new IndexedGraph();
            int          a   = g.AddNode();
            int          b   = g.AddNode();
            int          c   = g.AddNode();
            int          ab  = g.AddEdge(a, b);
            int          bb  = g.AddEdge(b, b); // self loop
            int          bc  = g.AddEdge(b, c);
            int          bc2 = g.AddEdge(b, c); // double edge

            Assert.Equal(c, g.TargetOf(bc));
            Assert.Equal(bb, g.GetEdge(b, b));
            Assert.Equal(0, g.EdgeCount(a, c));
            Assert.Equal(2, g.EdgeCount(b, c));
            Assert.Equal(4, g.EdgeCount());
            Assert.Equal(1, g.NeighborCount(a));
            Assert.Equal(2, g.NeighborCount(c));
            Assert.Equal(1, g.TargetCount(a));
            Assert.Equal(0, g.SourceCount(a));

            Console.Write("EdgesOf(b):");
            foreach (int edge in g.EdgesOf(b))
            {
                Console.Write(" {0}", edge);
            }
            Console.WriteLine();
            Console.Write("EdgesInto(b):");
            foreach (int edge in g.EdgesInto(b))
            {
                Console.Write(" {0}", edge);
            }
            Console.WriteLine();
            Console.Write("EdgesOutOf(b):");
            foreach (int edge in g.EdgesOutOf(b))
            {
                Console.Write(" {0}", edge);
            }
            Console.WriteLine();
            Console.Write("EdgesLinking(b,c):");
            foreach (int edge in g.EdgesLinking(b, c))
            {
                Console.Write(" {0}", edge);
            }
            Console.WriteLine();
        }
Ejemplo n.º 4
0
 protected override IExpression ConvertMethodInvoke(IMethodInvokeExpression imie)
 {
     if (imie.Method.Target is IThisReferenceExpression)
     {
         IMethodDeclaration imd = context.FindAncestor <IMethodDeclaration>();
         int sourceMethod       = GetMethodIndex(imd);
         int targetMethod       = GetMethodIndex(imie.Method.Method);
         MethodGraph.AddEdge(sourceMethod, targetMethod);
         //Trace.WriteLine($"{sourceMethod} {methods[sourceMethod].Name} called {targetMethod} {methods[targetMethod].Name}");
     }
     return(base.ConvertMethodInvoke(imie));
 }
Ejemplo n.º 5
0
        public void GroupGraphTest()
        {
            IndexedGraph g = new IndexedGraph(2);

            g.AddEdge(1, 0);
            int[]      groupOf    = new int[] { -1, 2, -1 };
            GroupGraph groupGraph = new GroupGraph(g, groupOf, g.Nodes.Count);

            groupGraph.BuildGroupEdges();
            var schedule = groupGraph.GetScheduleWithGroups(groupGraph.SourcesOf);

            Assert.True(schedule[0] == 1);
            Assert.True(schedule[1] == 0);
        }
Ejemplo n.º 6
0
        public DependencyGraph2(BasicTransformContext context,
                                IEnumerable <IStatement> inputs,
                                BackEdgeHandling backEdgeHandling,
                                Action <IWhileStatement> beginWhile,
                                Action <IWhileStatement> endWhile,
                                Action <IConditionStatement> beginFirstIterPost,
                                Action <IConditionStatement> endFirstIterPost,
                                Action <IStatement, NodeIndex> action)
        {
            Set <NodeIndex> nodesInCurrentWhile = new Set <EdgeIndex>();
            int             whileDepth          = 0;

            // create a dependency graph where while loops are flattened (the while loops themselves are not nodes)
            // the graph will only contain read-after-write and write-after-alloc dependencies for now
            // add write-after-read dependencies
            isWriteAfterRead = dependencyGraph.CreateEdgeData(false);
            DeadCodeTransform.ForEachStatement(inputs,
                                               delegate(IWhileStatement iws)
            {
                beginWhile(iws);
                nodesInCurrentWhile.Clear();
                whileDepth++;
            },
                                               delegate(IWhileStatement iws)
            {
                // all duplicates in a while loop should share all targets
                foreach (KeyValuePair <IStatement, Set <NodeIndex> > entry in duplicates)
                {
                    IStatement ist          = entry.Key;
                    Set <NodeIndex> set     = entry.Value;
                    Set <NodeIndex> targets = new Set <EdgeIndex>();
                    // collect all targets in the while loop
                    foreach (NodeIndex node in set)
                    {
                        foreach (NodeIndex target in dependencyGraph.TargetsOf(node))
                        {
                            if (nodesInCurrentWhile.Contains(target))
                            {
                                targets.Add(target);
                            }
                        }
                    }
                    Set <NodeIndex> backEdgeTargets = null;
                    if (!backEdges.TryGetValue(ist, out backEdgeTargets))
                    {
                        backEdgeTargets = new Set <EdgeIndex>();
                        backEdges[ist]  = backEdgeTargets;
                    }
                    // add all targets to all duplicates in the loop
                    foreach (NodeIndex node in set)
                    {
                        if (!nodesInCurrentWhile.Contains(node))
                        {
                            continue;
                        }
                        foreach (NodeIndex target in targets)
                        {
                            if (!dependencyGraph.ContainsEdge(node, target))
                            {
                                if (backEdgeHandling == BackEdgeHandling.Include)
                                {
                                    dependencyGraph.AddEdge(node, target);
                                }
                                else if (backEdgeHandling == BackEdgeHandling.Reverse)
                                {
                                    if (!dependencyGraph.ContainsEdge(target, node))
                                    {
                                        dependencyGraph.AddEdge(target, node);
                                    }
                                }
                                if (target < node)
                                {
                                    if (backEdgeTargets == null && !backEdges.TryGetValue(ist, out backEdgeTargets))
                                    {
                                        backEdgeTargets = new Set <EdgeIndex>();
                                        backEdges[ist]  = backEdgeTargets;
                                    }
                                    backEdgeTargets.Add(target);
                                }
                            }
                        }
                    }
                }
                endWhile(iws);
                whileDepth--;
            },
                                               beginFirstIterPost,
                                               endFirstIterPost,
                                               delegate(IStatement ist)
            {
                DependencyInformation di = context.InputAttributes.Get <DependencyInformation>(ist);
                if (di == null)
                {
                    context.Error("Dependency information not found for statement: " + ist);
                    di = new DependencyInformation();
                }
                NodeIndex targetIndex = dependencyGraph.AddNode();
                Set <NodeIndex> backEdgeTargets;
                Set <NodeIndex> sources = new Set <NodeIndex>();                                  // for fast checking of duplicate sources
                foreach (IStatement source in
                         di.GetDependenciesOfType(DependencyType.Dependency | DependencyType.Declaration))
                {
                    int sourceIndex;
                    // we assume that the statements are already ordered properly to respect dependencies.
                    // if the source is not in indexOfNode, then it must be a cyclic dependency in this while loop.
                    if (indexOfNode.TryGetValue(source, out sourceIndex))
                    {
                        if (!sources.Contains(sourceIndex))
                        {
                            sources.Add(sourceIndex);
                            EdgeIndex edge = dependencyGraph.AddEdge(sourceIndex, targetIndex);
                        }
                    }
                    else
                    {
                        sourceIndex = -1;
                    }
                    if (sourceIndex == -1)
                    {
                        // add a back edge
                        if (!backEdges.TryGetValue(source, out backEdgeTargets))
                        {
                            backEdgeTargets   = new Set <EdgeIndex>();
                            backEdges[source] = backEdgeTargets;
                        }
                        backEdgeTargets.Add(targetIndex);
                        // add a dependency on the initializers of source
                        Stack <IStatement> todo = new Stack <IStatement>();
                        todo.Push(source);
                        while (todo.Count > 0)
                        {
                            IStatement source2        = todo.Pop();
                            DependencyInformation di2 = context.InputAttributes.Get <DependencyInformation>(source2);
                            if (di2 == null)
                            {
                                context.Error("Dependency information not found for statement: " + source2);
                                continue;
                            }
                            foreach (IStatement init in di2.Overwrites)
                            {
                                int initIndex;
                                if (indexOfNode.TryGetValue(init, out initIndex))
                                {
                                    if (!sources.Contains(initIndex))
                                    {
                                        sources.Add(initIndex);
                                        EdgeIndex edge = dependencyGraph.AddEdge(initIndex, targetIndex);
                                    }
                                }
                                else
                                {
                                    todo.Push(init);
                                }
                            }
                        }
                    }
                }
                if (indexOfNode.ContainsKey(ist))
                {
                    Set <int> set;
                    if (!duplicates.TryGetValue(ist, out set))
                    {
                        set             = new Set <int>();
                        duplicates[ist] = set;
                        set.Add(indexOfNode[ist]);
                    }
                    set.Add(targetIndex);
                }
                // the same statement may appear multiple times.  when looking up indexOfNode, we want to use the last occurrence of the statement.
                indexOfNode[ist] = targetIndex;                                    // must do this at the end, in case the stmt depends on a previous occurrence of itself
                nodesInCurrentWhile.Add(targetIndex);
                nodes.Add(ist);
                if (backEdgeHandling != BackEdgeHandling.Ignore && backEdges.TryGetValue(ist, out backEdgeTargets))
                {
                    // now that ist has an index, we can fill in the back edges
                    foreach (NodeIndex node in backEdgeTargets)
                    {
                        if (backEdgeHandling == BackEdgeHandling.Include)
                        {
                            if (dependencyGraph.ContainsEdge(targetIndex, node))
                            {
                                throw new Exception("Internal: back edge already present");
                            }
                            dependencyGraph.AddEdge(targetIndex, node);
                        }
                        else
                        {
                            // make a new edge, even if one exists.
                            EdgeIndex edge         = dependencyGraph.AddEdge(node, targetIndex);
                            isWriteAfterRead[edge] = true;
                        }
                    }
                }
                action(ist, targetIndex);
            });
            if (string.Empty.Length > 0)
            {
                // loop statements in their original order
                foreach (NodeIndex target in dependencyGraph.Nodes)
                {
                    IStatement ist = nodes[target];
                    if (ist is IWhileStatement)
                    {
                        continue;
                    }
                    foreach (NodeIndex source in GetPreviousReaders(context, dependencyGraph, target, nodes, indexOfNode).ToReadOnlyList())
                    {
                        if (source > target)
                        {
                            throw new Exception("Internal: source statement follows target");
                        }
                        // make a new edge, even if one exists.
                        EdgeIndex edge = dependencyGraph.AddEdge(source, target);
                        isWriteAfterRead[edge] = true;
                    }
                }
            }
            isWriteAfterWrite = dependencyGraph.CreateEdgeData(false);
            // loop statements in their original order
            foreach (NodeIndex target in dependencyGraph.Nodes)
            {
                IStatement ist = nodes[target];
                if (ist is IWhileStatement)
                {
                    continue;
                }

                foreach (NodeIndex source in GetOverwrites(context, dependencyGraph, target, nodes, indexOfNode).ToReadOnlyList())
                {
                    if (source > target)
                    {
                        throw new Exception("Internal: source statement follows target");
                    }
                    if (dependencyGraph.ContainsEdge(source, target))
                    {
                        foreach (EdgeIndex edge in dependencyGraph.EdgesLinking(source, target))
                        {
                            isWriteAfterWrite[edge] = true;
                        }
                    }
                    else
                    {
                        EdgeIndex edge = dependencyGraph.AddEdge(source, target);
                        isWriteAfterWrite[edge] = true;
                    }
                }
            }

            dependencyGraph.NodeCountIsConstant = true;
            dependencyGraph.IsReadOnly          = true;
            for (int targetIndex = 0; targetIndex < dependencyGraph.Nodes.Count; targetIndex++)
            {
                IStatement            ist = nodes[targetIndex];
                DependencyInformation di  = context.InputAttributes.Get <DependencyInformation>(ist);
                if (di == null)
                {
                    continue;
                }
                if (di.IsOutput)
                {
                    outputNodes.Add(targetIndex);
                }
            }
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
#pragma warning restore 162
#endif

        private void PostProcess()
        {
            // create a dependency graph between MethodInvokes
            Dictionary <IVariableDeclaration, List <int> > mutationsOfVariable = new Dictionary <IVariableDeclaration, List <NodeIndex> >();
            IndexedGraph g = new IndexedGraph(factorExprs.Count);

            foreach (NodeIndex node in g.Nodes)
            {
                IExpression factor = factorExprs[node];
                NodeInfo    info   = GetNodeInfo(factor);
                for (int i = 0; i < info.arguments.Count; i++)
                {
                    if (info.isReturnOrOut[i])
                    {
                        // this is a mutation.  add to mutationsOfVariable.
                        IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(info.arguments[i]);
                        if (ivd != null && CodeRecognizer.IsStochastic(context, ivd))
                        {
                            List <int> nodes;
                            if (!mutationsOfVariable.TryGetValue(ivd, out nodes))
                            {
                                nodes = new List <NodeIndex>();
                                mutationsOfVariable[ivd] = nodes;
                            }
                            nodes.Add(node);
                        }
                    }
                }
            }
            foreach (NodeIndex node in g.Nodes)
            {
                IExpression factor = factorExprs[node];
                NodeInfo    info   = GetNodeInfo(factor);
                for (int i = 0; i < info.arguments.Count; i++)
                {
                    if (!info.isReturnOrOut[i])
                    {
                        // not a mutation.  create a dependency on all mutations.
                        IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(info.arguments[i]);
                        if (ivd != null && CodeRecognizer.IsStochastic(context, ivd))
                        {
                            foreach (NodeIndex source in mutationsOfVariable[ivd])
                            {
                                g.AddEdge(source, node);
                            }
                        }
                    }
                }
            }
            List <NodeIndex>             topo_nodes = new List <NodeIndex>();
            DepthFirstSearch <NodeIndex> dfs        = new DepthFirstSearch <NodeIndex>(g.SourcesOf, g);

            dfs.FinishNode += delegate(NodeIndex node)
            {
                IExpression factor = factorExprs[node];
                ProcessFactor(factor, MessageDirection.Forwards);
                topo_nodes.Add(node);
            };
            // process nodes forward
            dfs.SearchFrom(g.Nodes);
            // process nodes backward
            for (int i = topo_nodes.Count - 1; i >= 0; i--)
            {
                NodeIndex   node   = topo_nodes[i];
                IExpression factor = factorExprs[node];
                ProcessFactor(factor, MessageDirection.Backwards);
            }
        }