Ejemplo n.º 1
0
        public Tuple <CCS, double[]> CalculateDisplacementPermutation(CCS a)
        {
            var totDofCount = a.ColumnCount - 1;


            var allEqs = a;


            //var empties = allEqs.EmptyRowCount();

            //var dns = allEqs.ToDenseMatrix();


            #region comment

            /*
             #region step 2
             * //step 2: create adjacency matrix of variables
             *
             * //step 2-1: find nonzero pattern
             * var allEqsNonzeroPattern = allEqs.Clone();
             *
             * for (var i = 0; i < allEqsNonzeroPattern.Values.Length; i++)
             *  allEqsNonzeroPattern.Values[i] = 1;
             *
             * //https://math.stackexchange.com/questions/2340450/extract-independent-sub-systems-from-a-bigger-linear-eq-system
             * var tmp = allEqsNonzeroPattern.Transpose();
             *
             * var variableAdj = tmp.Multiply(allEqsNonzeroPattern);
             #endregion
             *
             #region step 3
             * //extract parts
             * var parts = EnumerateGraphParts(variableAdj);
             *
             #endregion
             *
             #region step 4
             * {
             *
             *  allEqs.EnumerateColumns((colNum, vals) =>
             *  {
             *      if (vals.Count == 0)
             *      Console.WriteLine("Col {0} have {1} nonzeros", colNum, vals.Count);
             *  });
             *
             *  var order = ColumnOrdering.MinimumDegreeAtPlusA;
             *
             *  // Partial pivoting tolerance (0.0 to 1.0)
             *  double tolerance = 1.0;
             *
             *  var lu = CSparse.Double.Factorization.SparseLU.Create(allEqs, order, tolerance);
             *
             * }
             *
             #endregion
             */

            #endregion

            var rrefFinder = new GaussRrefFinder();

            var rref = rrefFinder.CalculateRref(allEqs);

            var rrefSys = SparseEqSystem.Generate(rref);

            #region generate P_Delta

            var pRows = new int[totDofCount]; // pRows[i] = index of equation that its right side is Di (ai*Di = a1*D1+...+an*Dn)

            pRows.FillWith(-1);

            for (var i = 0; i < rrefSys.RowCount; i++)
            {
                foreach (var tpl in rrefSys.Equations[i].EnumerateIndexed())
                {
                    if (rrefSys.ColumnNonzeros[tpl.Item1] == 1)
                    {
                        if (pRows[tpl.Item1] != -1)
                        {
                            throw new Exception();
                        }

                        pRows[tpl.Item1] = i;
                    }
                }
            }

            int cnt = 0;

            var lastColIndex = rrefSys.ColumnCount - 1;

            var p2Coord = new CoordinateStorage <double>(totDofCount, totDofCount, 1);

            var rightSide = new double[totDofCount];



            for (var i = 0; i < totDofCount; i++)
            {
                if (pRows[i] == -1)
                {
                    p2Coord.At(i, i, 1);
                    continue;
                }

                var eq = rrefSys.Equations[pRows[i]];
                eq.Multiply(-1 / eq.GetMember(i));

                var minus1 = eq.GetMember(i);

                if (!minus1.FEquals(-1, 1e-9))
                {
                    throw new Exception();
                }

                //eq.SetMember(i, 0);

                foreach (var tpl in eq.EnumerateIndexed())
                {
                    if (tpl.Item1 != lastColIndex)
                    {
                        p2Coord.At(i, tpl.Item1, tpl.Item2);
                    }
                    else
                    {
                        rightSide[i] = tpl.Item2;
                    }
                }
            }



            cnt = 0;

            foreach (var eq in rrefSys.Equations)
            {
                if (eq.IsZeroRow(1e-9))
                {
                    cnt++;
                }
            }

            #endregion

            var p2 = p2Coord.ToCCs();

            var colsToRemove = new bool[totDofCount];

            var colNumPerm = new int[totDofCount];

            colNumPerm.FillWith(-1);

            colsToRemove.FillWith(false);

            var tmp = 0;

            for (var i = 0; i < rrefSys.ColumnNonzeros.Length; i++)
            {
                if (i != lastColIndex)
                {
                    if (rrefSys.ColumnNonzeros[i] == 1)
                    {
                        colsToRemove[i] = true;
                    }
                    else
                    {
                        colNumPerm[i] = tmp++;
                    }
                }
            }


            var p3Crd = new CoordinateStorage <double>(totDofCount, totDofCount - colsToRemove.Count(i => i), 1);

            foreach (var tpl in p2.EnumerateIndexed2())
            {
                if (!colsToRemove[tpl.Item2])
                {
                    p3Crd.At(tpl.Item1, colNumPerm[tpl.Item2], tpl.Item3);
                }
            }

            var p3 = p3Crd.ToCCs();

            return(Tuple.Create(p3, rightSide));
        }
Ejemplo n.º 2
0
        public CCS CalculateRref(CCS a)
        {
            var sys = SparseEqSystem.Generate((CSparse.Double.CompressedColumnStorage)a);

            var dns = a.ToDenseMatrix();

            sys.RowsPool = new SortedSet <SparseRow>();

            var eqs = sys.Equations;

            for (var i = 0; i < sys.Equations.Length; i++)
            {
                sys.Equations[i].Tag = i;
            }

            var lastColIndex = a.ColumnCount - 1;

            //should have n columns with one nonzero

            //var colPivotHistory = new HashSet<int>();
            //var rowPivotHistory = new HashSet<int>();
            var dependentRows = new bool[sys.RowCount];// HashSet<int>();
            var leadingMember = new bool[sys.RowCount];


            //var pivotedYet = new bool[a.RowCount];

            for (var i = 0; i < sys.Equations.Length; i++)
            {
                foreach (var tuple in sys.Equations[i].EnumerateIndexed())
                {
                    if (sys.ColumnNonzeros[tuple.Item1] == 1)
                    {
                        leadingMember[i] = true;
                    }
                }
            }


            var maxItter = Math.Max(a.ColumnCount, a.RowCount);

            var itter = 0;

            while (itter++ < maxItter)
            {
                //find count
                var oneNnzCols = sys.ColumnNonzeros.Count(i => i == 1);

                var eqNeeded = Math.Min(a.ColumnCount - 1, a.RowCount - dependentRows.Count(i => i == true));


                if (oneNnzCols == eqNeeded)
                {
                    break;
                }

                //select pivot
                //minimum row nnz x col nnz
                //select row strategy: row with minimum nnz, where nnz is nonzero count except last column (right side) and nnz > 1


                var minRowNnz      = int.MaxValue; // sys.RowNonzeros.Where(i => i > 1).Min();
                var minRowNnzIndex = -1;           // sys.RowNonzeros.FirstIndexOf(minRowNnz);

                {
                    for (var j = 0; j < sys.RowCount; j++)
                    {
                        if (leadingMember[j])
                        {
                            continue;
                        }

                        if (dependentRows[j])
                        {
                            continue;
                        }


                        //if (sys.RowNonzeros[j] <= 1)
                        //    continue;

                        if (sys.RowNonzeros[j] < minRowNnz)
                        {
                            minRowNnzIndex = j;
                            minRowNnz      = sys.RowNonzeros[j];
                        }
                    }
                }

                if (minRowNnzIndex == -1)
                {
                    throw new Exception();
                }


                //var minColNnz = sys.ColumnNonzeros.Where(i => i > 1).Min();
                var minColNnz      = int.MaxValue;// sys.ColumnNonzeros.Where(i => i > 1).Min();
                var minColNnzIndex = -1;


                {
                    for (var jj = 0; jj < sys.Equations[minRowNnzIndex].Size; jj++)
                    {
                        var j = sys.Equations[minRowNnzIndex].Indexes[jj];

                        //if (colPivotHistory.Contains(j))
                        //    continue;

                        if (sys.ColumnNonzeros[j] <= 1)
                        {
                            continue;
                        }

                        if (sys.ColumnNonzeros[j] < minColNnz)
                        {
                            minColNnzIndex = j;
                            minColNnz      = sys.ColumnNonzeros[j];
                        }
                    }
                }

                //var minColNnzIndex = sys.ColumnNonzeros.FirstIndexOf(minColNnz);



                if (minColNnzIndex == -1)
                {
                    //var t = sys.ToCcs().ToDenseMatrix();

                    throw new Exception();
                }

                var col = minColNnzIndex;


                var c1 = sys.Equations.Where(i => i.ContainsIndex(col) && !leadingMember[i.Tag]);

                var rw =
                    c1.MinBy(j => j.Size, null);
                //sys.Equations[minRowNnzIndex];

                if (dependentRows[sys.Equations.IndexOfReference(rw)])
                {
                    throw new Exception();
                }

                Console.WriteLine("Pivot: {0},{1}", sys.Equations.IndexOfReference(rw), col);

                //Console.ReadKey();
                // eqs.Equations.Where(i => i.Size > 1).MinBy(new SparseRowLengthComparer());

                var eliminator = rw;// sys.Equations[rw];

                //eliminate all rows with pivot
                for (var i = 0; i < sys.Equations.Length; i++)
                {
                    var canditate = eqs[i];

                    if (canditate.ContainsIndex(col) && !ReferenceEquals(eliminator, canditate))
                    {
                        var oldOne = eqs[i];//to be removed

                        foreach (var enm in oldOne.EnumerateIndexed())
                        {
                            sys.ColumnNonzeros[enm.Item1]--;
                        }

                        var newOne = SparseRow.Eliminate(eliminator, oldOne, col);

                        if (newOne.CalcNnz(lastColIndex) == 0 && newOne.GetRightSideValue(lastColIndex) != 0)
                        {
                            throw new Exception("Inconsistent system");
                        }

                        if (newOne.CalcNnz(lastColIndex) == 0 && newOne.GetRightSideValue(lastColIndex) == 0)
                        {
                            //fully zero equation
                            dependentRows[i] = true;// newOne.Tag);
                        }



                        newOne.Tag = oldOne.Tag;

                        foreach (var enm in newOne.EnumerateIndexed())
                        {
                            sys.ColumnNonzeros[enm.Item1]++;

                            if (sys.ColumnNonzeros[enm.Item1] == 1)
                            {
                                leadingMember[i] = true;
                            }
                        }


                        if (sys.ColumnNonzeros.Contains(0))
                        {
                            Guid.NewGuid();
                        }

                        eqs[i] = newOne;

                        sys.RowNonzeros[i] = newOne.CalcNnz(lastColIndex);
                    }
                }

                leadingMember[sys.Equations.IndexOfReference(rw)] = true;

                Console.WriteLine("elimination done for all eqs, Col[{0}] : {1} nnzs", col, sys.ColumnNonzeros[col]);

                if (sys.ColumnNonzeros[col] != 1)
                {
                    Guid.NewGuid();
                }
            }

            SparseEqSystem newSys;// = new SparseEqSystem();

            {
                ////////start final check

                var tol = 1e-9;

                var dependentEquationCount   = sys.Equations.Count(i => i.CalcNnz(lastColIndex) == 0 && i.GetRightSideValue(lastColIndex).FEquals(0, tol));
                var incosistentEquationCount = sys.Equations.Count(i => i.CalcNnz(lastColIndex) == 0 && !i.GetRightSideValue(lastColIndex).FEquals(0, tol));
                var NnzMemberInCol           = new int[sys.ColumnCount - 1];

                foreach (var eq in sys.Equations)
                {
                    foreach (var idx in eq.EnumerateIndexed())
                    {
                        if (idx.Item1 != lastColIndex)
                        {
                            if (!idx.Item2.FEquals(0, tol))
                            {
                                NnzMemberInCol[idx.Item1]++;
                            }
                        }
                    }
                }

                var leadingMembers = NnzMemberInCol.Count(i => i == 1);

                if (leadingMembers != Math.Min(sys.ColumnCount - 1, sys.RowCount - dependentEquationCount))
                {
                    throw new Exception();
                }

                if (incosistentEquationCount != 0)
                {
                    throw new Exception();
                }

                var allExceptDependentEqs = sys.Equations.Where(i => !(i.CalcNnz(lastColIndex) == 0 && i.GetRightSideValue(lastColIndex).FEquals(0, tol))).ToArray();

                newSys = SparseEqSystem.Generate(allExceptDependentEqs, a.ColumnCount);
            }

            return(newSys.ToCcs());
        }