internal override (NodeDataMap MfpIn, NodeDataMap MfpOut) _Solve(Func <FlowNode, ISet <VariableDescriptor>, ISet <VariableDescriptor> > transferFunction) { // Custom solver is necessary because of the side-effects of the merge function var worklist = new Queue <FlowNode>(Nodes); var mfpIn = Nodes.ToDictionary(node => node, node => _emptySet); var mfpOut = Nodes.ToDictionary(node => node, node => _emptySet); var transitions = _ConstructTransitions(); while (worklist.Count > 0) { var node = worklist.Dequeue(); var merged = ExtremalNodes.Contains(node) ? ExtremalValues : _Merge(transitions.Predecessors[node].SelectMany(predecessor => mfpOut[predecessor]).ToImmutableHashSet()); var transferred = transferFunction(node, merged); // Merging may have changed the data, thus it is always updated (not necessary to check for changes). // But only for cases wherethe data after transfer changed make it necessary to notify the successors about the change. mfpIn[node] = merged; if (!IncreasesAnalysisKnowledge(transferred, mfpOut[node])) { continue; } mfpOut[node] = transferred; worklist.EnqueueAll(transitions.Successors[node]); } return(mfpIn, mfpOut); }
internal virtual (IDictionary <FlowNode, ISet <TData> > MfpIn, IDictionary <FlowNode, ISet <TData> > MfpOut) _Solve(Func <FlowNode, ISet <TData>, ISet <TData> > transferFunction) { var worklist = new Queue <FlowTransition>(Flow); var analysis = Nodes.ToDictionary(node => node, node => ExtremalNodes.Contains(node) ? ExtremalValues : LeastValues); while (worklist.Count > 0) { var transition = worklist.Dequeue(); var transferred = transferFunction(transition.First, analysis[transition.First]); if (!IncreasesAnalysisKnowledge(transferred, analysis[transition.Second])) { continue; } analysis[transition.Second] = Merge(transferred, analysis[transition.Second]); //worklist.EnqueueAll(Flow.Where(flow => flow.First.Equals(transition.Second))); worklist.EnqueueAll(Flow.Where(flow => flow.First == transition.Second)); } return(analysis, analysis.ToDictionary(entry => entry.Key, entry => Transfer(entry.Key, entry.Value))); }