private EquationDecomposition(EquationSystem eqsys)
        {
            /** This algorithm decomposes a given equation system into smaller equation blocks
             *  which can be solved subsequently. The algorithm is sometimes referred to as
             *  Tarjan's sorting or Dulmage-Mendelson decomposition.
             *  
             *  The algorithm consists of several steps. The description below will use the
             *  following notions:
             *    Var: The set of variables of the whole equation system
             *    Eqn: The set of equations of the whole equation system
             *    Var u Eqn: The set unification of Var and Eqn
             *  
             *  Step (1): Maximum matching
             *    Define an undirected graph G = (V, E) with V = Var u Eqn.
             *    Whenever an equation eqn \in Eqn references a variable var \in Var
             *    add the edge (eqn, var) to E.
             *    Compute a maximum matching M between variables and equations.
             *    M will now contain a set of equation/variable pairs.
             *    
             * Step (2): Finding strongly connected components
             *    Define a directed graph Gd = (V, Ed) with V = Var u Eqn.
             *    Whenever an equation eqn \in Eqn references a variable var \in Var
             *    add the edge (eqn, var) to Ed.
             *    For each equation/variable pair (eqn, var) in M add furthermore
             *    the edge (var, eqn) to Ed.
             *    Note: Matched equation/variable pairs will result in bi-directional edges in Ed.
             *    Compute the strongly connected components SCC of Gd.
             *    SCC is a set of subsets of V such that each subset represents one component.
             *    
             * Step (3): Building the tree of equation blocks
             *    Defined a directed graph Dt = (SCC, Et).
             *    For each equation eqn \in Eqn which is assigned to component c1 and
             *    references a variable var \in Var which is assigned to component c2
             *    add an edge (c1, c2) to Et of c1 and c2 are different.
             *    
             *    The resulting graph will have a tree/forest sutrcture. Each node
             *    represents an equation block. An edge b1 -> b2 represents a dependency in the
             *    that b2 must be solved prior to b1. A schedule can be found by topological 
             *    sorting the tree.
             * */

            if (eqsys == null ||
                eqsys.Equations == null ||
                eqsys.Variables == null)
                throw new ArgumentException("null reference in equation system argument");

            if (eqsys.Equations.Count != eqsys.Variables.Count)
                throw new ArgumentException("equation system is not well-constrained!");

            /** Assign each equation and each variable an index which will be a unique node
             * ID within the graphs. Indices are assigned as follows:
             *   - Equations get indices from 0...count(equations)-1
             *   - Variables get indices from count(equations)...count(equations)+count(variables)
             *   Note: Assuming a well-constrained equation system, count(equations) = count(variables)
             **/
            int curidx = 0;
            foreach (Expression eq in eqsys.Equations)
            {
                eq.Cookie = curidx++;
            }
            Dictionary<object, int> idx = new Dictionary<object, int>();
            foreach (Variable v in eqsys.Variables)
            {
                idx[v] = curidx++;
            }

            // Steps 1 and 2: Construct G and Gd
            Graph g = new Graph(curidx);
            Digraph dg = new Digraph(curidx);
            for (int i = 0; i < eqsys.Equations.Count; i++)
            {
                Expression eq = eqsys.Equations[i];
                LiteralReference[] lrs = eq.ExtractLiteralReferences();
                foreach (LiteralReference lr in lrs)
                {
                    int j;
                    if (idx.TryGetValue(lr.ReferencedObject, out j))
                    {
                        g.AddEdge(i, j);
                        dg.AddEdge(i, j);
                    }
                }
            }
            // Step 1: Maximum matching
            GraphAlgorithms.Matching m = g.GetMaximumMatching();
            bool success = m.IsMaximumCardinality;
            for (int i = 0; i < eqsys.Equations.Count; i++)
            {
                int k = m[i];
                if (k >= 0)
                    dg.AddEdge(k, i);
            }
            // Step 2: Strongly connected components
            StrongComponents sc = dg.GetStrongComponents();
            int numc = sc.NumComponents;
            EquationBlock[] blocks = new EquationBlock[numc];
            for (int i = 0; i < numc; i++)
            {
                blocks[i] = new EquationBlock();
            }

            // Step 3: Construct the tree
            Digraph dg2 = new Digraph(numc);
            for (int i = 0; i < eqsys.Equations.Count; i++)
            {
                int c = sc[i];
                blocks[c].EqSys.Equations.Add(eqsys.Equations[i]);
                int vi = m[i];
                Variable v = eqsys.Variables[vi - eqsys.Equations.Count];
                blocks[c].EqSys.Variables.Add(v);
                List<int> outset = dg.GetOutSet(i);
                foreach (int ovi in outset)
                {
                    int oc = sc[ovi];
                    if (c != oc)
                        dg2.AddEdge(c, oc);
                }
            }
            List<int> rootSet = new List<int>();
            List<int> sinkSet = new List<int>();
            for (int c = 0; c < numc; c++)
            {
                if (dg2.GetOutDegree(c) == 0)
                    rootSet.Add(c);
                if (dg2.GetInDegree(c) == 0)
                    sinkSet.Add(c);
                List<int> outset = dg2.GetOutSet(c);
                foreach (int oc in outset)
                    blocks[c].Predecessors.Add(blocks[oc]);
                List<int> inset = dg2.GetInSet(c);
                foreach (int ic in inset)
                    blocks[c].Successors.Add(blocks[ic]);
            }
            RootSet = (from int c in rootSet
                       select blocks[c]).ToArray();
            SinkSet = (from int c in sinkSet
                       select blocks[c]).ToArray();
            AllBlocks = blocks;
        }
Example #2
0
        private EquationDecomposition(EquationSystem eqsys)
        {
            /** This algorithm decomposes a given equation system into smaller equation blocks
             *  which can be solved subsequently. The algorithm is sometimes referred to as
             *  Tarjan's sorting or Dulmage-Mendelson decomposition.
             *
             *  The algorithm consists of several steps. The description below will use the
             *  following notions:
             *    Var: The set of variables of the whole equation system
             *    Eqn: The set of equations of the whole equation system
             *    Var u Eqn: The set unification of Var and Eqn
             *
             *  Step (1): Maximum matching
             *    Define an undirected graph G = (V, E) with V = Var u Eqn.
             *    Whenever an equation eqn \in Eqn references a variable var \in Var
             *    add the edge (eqn, var) to E.
             *    Compute a maximum matching M between variables and equations.
             *    M will now contain a set of equation/variable pairs.
             *
             * Step (2): Finding strongly connected components
             *    Define a directed graph Gd = (V, Ed) with V = Var u Eqn.
             *    Whenever an equation eqn \in Eqn references a variable var \in Var
             *    add the edge (eqn, var) to Ed.
             *    For each equation/variable pair (eqn, var) in M add furthermore
             *    the edge (var, eqn) to Ed.
             *    Note: Matched equation/variable pairs will result in bi-directional edges in Ed.
             *    Compute the strongly connected components SCC of Gd.
             *    SCC is a set of subsets of V such that each subset represents one component.
             *
             * Step (3): Building the tree of equation blocks
             *    Defined a directed graph Dt = (SCC, Et).
             *    For each equation eqn \in Eqn which is assigned to component c1 and
             *    references a variable var \in Var which is assigned to component c2
             *    add an edge (c1, c2) to Et of c1 and c2 are different.
             *
             *    The resulting graph will have a tree/forest sutrcture. Each node
             *    represents an equation block. An edge b1 -> b2 represents a dependency in the
             *    that b2 must be solved prior to b1. A schedule can be found by topological
             *    sorting the tree.
             * */

            if (eqsys == null ||
                eqsys.Equations == null ||
                eqsys.Variables == null)
            {
                throw new ArgumentException("null reference in equation system argument");
            }

            if (eqsys.Equations.Count != eqsys.Variables.Count)
            {
                throw new ArgumentException("equation system is not well-constrained!");
            }

            /** Assign each equation and each variable an index which will be a unique node
             * ID within the graphs. Indices are assigned as follows:
             *   - Equations get indices from 0...count(equations)-1
             *   - Variables get indices from count(equations)...count(equations)+count(variables)
             *   Note: Assuming a well-constrained equation system, count(equations) = count(variables)
             **/
            int curidx = 0;

            foreach (Expression eq in eqsys.Equations)
            {
                eq.Cookie = curidx++;
            }
            Dictionary <object, int> idx = new Dictionary <object, int>();

            foreach (Variable v in eqsys.Variables)
            {
                idx[v] = curidx++;
            }

            // Steps 1 and 2: Construct G and Gd
            Graph   g  = new Graph(curidx);
            Digraph dg = new Digraph(curidx);

            for (int i = 0; i < eqsys.Equations.Count; i++)
            {
                Expression         eq  = eqsys.Equations[i];
                LiteralReference[] lrs = eq.ExtractLiteralReferences();
                foreach (LiteralReference lr in lrs)
                {
                    int j;
                    if (idx.TryGetValue(lr.ReferencedObject, out j))
                    {
                        g.AddEdge(i, j);
                        dg.AddEdge(i, j);
                    }
                }
            }
            // Step 1: Maximum matching
            GraphAlgorithms.Matching m = g.GetMaximumMatching();
            bool success = m.IsMaximumCardinality;

            for (int i = 0; i < eqsys.Equations.Count; i++)
            {
                int k = m[i];
                if (k >= 0)
                {
                    dg.AddEdge(k, i);
                }
            }
            // Step 2: Strongly connected components
            StrongComponents sc = dg.GetStrongComponents();
            int numc            = sc.NumComponents;

            EquationBlock[] blocks = new EquationBlock[numc];
            for (int i = 0; i < numc; i++)
            {
                blocks[i] = new EquationBlock();
            }

            // Step 3: Construct the tree
            Digraph dg2 = new Digraph(numc);

            for (int i = 0; i < eqsys.Equations.Count; i++)
            {
                int c = sc[i];
                blocks[c].EqSys.Equations.Add(eqsys.Equations[i]);
                int      vi = m[i];
                Variable v  = eqsys.Variables[vi - eqsys.Equations.Count];
                blocks[c].EqSys.Variables.Add(v);
                List <int> outset = dg.GetOutSet(i);
                foreach (int ovi in outset)
                {
                    int oc = sc[ovi];
                    if (c != oc)
                    {
                        dg2.AddEdge(c, oc);
                    }
                }
            }
            List <int> rootSet = new List <int>();
            List <int> sinkSet = new List <int>();

            for (int c = 0; c < numc; c++)
            {
                if (dg2.GetOutDegree(c) == 0)
                {
                    rootSet.Add(c);
                }
                if (dg2.GetInDegree(c) == 0)
                {
                    sinkSet.Add(c);
                }
                List <int> outset = dg2.GetOutSet(c);
                foreach (int oc in outset)
                {
                    blocks[c].Predecessors.Add(blocks[oc]);
                }
                List <int> inset = dg2.GetInSet(c);
                foreach (int ic in inset)
                {
                    blocks[c].Successors.Add(blocks[ic]);
                }
            }
            RootSet = (from int c in rootSet
                       select blocks[c]).ToArray();
            SinkSet = (from int c in sinkSet
                       select blocks[c]).ToArray();
            AllBlocks = blocks;
        }