//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System.Collections.Generic; using Microsoft.Contracts; namespace Microsoft.Boogie { public delegate System.Collections.IEnumerable/**/! Adjacency(T! node); // An SCC is a set of nodes public sealed class SCC : ICollection { private IDictionary! nodesMap = new Dictionary(); private ICollection! nodes { get { return (!) nodesMap.Keys; } } [Pure] [GlobalAccess(false)] [Escapes(true,false)] System.Collections.IEnumerator! System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)nodes).GetEnumerator(); } [Pure] [GlobalAccess(false)] [Escapes(true,false)] IEnumerator! IEnumerable.GetEnumerator() { return ((IEnumerable)nodes).GetEnumerator(); } public int Count { get { return nodes.Count; } } public bool IsReadOnly { get { return nodesMap.IsReadOnly; } } public void Add(Node item) { nodesMap.Add(item,null); } public void Clear() { nodesMap.Clear(); } [Pure] public bool Contains(Node item) { return nodesMap.ContainsKey(item); } public void CopyTo(Node[]! array, int arrayIndex) { nodes.CopyTo(array, arrayIndex); } public bool Remove(Node item) { return nodesMap.Remove(item); } } public sealed class StronglyConnectedComponents : IEnumerable!> { private readonly IDictionary! graph; private readonly Adjacency! preds; private readonly Adjacency! succs; private bool computed = false; public bool Computed { get { return computed; } } [NotDelayed] public StronglyConnectedComponents(System.Collections.IEnumerable/**/! graph, Adjacency! preds, Adjacency! succs) ensures !Computed; { IDictionary! dict = new Dictionary(); foreach (Node! n in graph) { dict.Add(n,null); } this.graph = dict; this.preds = preds; this.succs = succs; base(); } [Pure] [GlobalAccess(false)] [Escapes(true,false)] System.Collections.IEnumerator! System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)sccs).GetEnumerator(); } [Pure] [GlobalAccess(false)] [Escapes(true,false)] IEnumerator!>! IEnumerable!>.GetEnumerator() { assume Computed; return ((IEnumerable!>)sccs).GetEnumerator(); } private readonly IList!>! sccs = new List!>(); public void Compute() requires !Computed; ensures Computed; { // Compute post times on graph with edges reversed this.dfsNext = this.preds; foreach (Node! n in (!)graph.Keys) { if (!seen.ContainsKey(n)) { OrderNodes(n); } } // Clear seen seen.Clear(); // Compute SCCs this.dfsNext = this.succs; while (postOrder.Count > 0) { Node! n = postOrder.Pop(); if (!seen.ContainsKey(n)) { SCC! curr = new SCC(); FindSCCs(n, curr); sccs.Add(curr); } } // Clear seen seen.Clear(); this.computed = true; } private Adjacency/*?*/ dfsNext = null; private readonly IDictionary! seen = new Dictionary(); private readonly Stack! postOrder = new Stack(); // DFS to order nodes by post times private void OrderNodes(Node! node) { seen.Add(node,null); assert dfsNext != null; System.Collections.IEnumerable! nexts = dfsNext(node); foreach (Node! n in nexts) { if (graph.ContainsKey(n) && !seen.ContainsKey(n)) { OrderNodes(n); } } postOrder.Push(node); } // DFS to compute SCCs private void FindSCCs(Node! node, SCC! currSCC) //modifies currSCC.*; { seen.Add(node,null); currSCC.Add(node); assert dfsNext != null; System.Collections.IEnumerable! nexts = dfsNext(node); foreach (Node! n in nexts) { if (graph.ContainsKey(n) && !seen.ContainsKey(n)) { FindSCCs(n,currSCC); } } } [Pure] public override string! ToString() { string outStr = ""; int i = 0; foreach(ICollection component in this) { string! tmp = System.String.Format("\nComponent #{0} = ", i++); outStr += tmp; bool firstInRow = true; foreach(Node b in component) { string! tmpComponent = System.String.Format("{0}{1}", firstInRow? "" : ", ", b); outStr += tmpComponent; firstInRow = false; } } return outStr; } } }