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)); }
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()); }