/// <summary> /// Adds the specified sparse rows regarding defined multipliers. /// </summary> /// <param name="a1">The a1.</param> /// <param name="a2">The a2.</param> /// <param name="a1Coef">The a1 coef.</param> /// <param name="a2Coef">The a2 coef.</param> /// <returns> a1 * a1Coef + a2 * a2Coef</returns> public static SparseRow Add(SparseRow a1, SparseRow a2, double a1Coef, double a2Coef) { var buf = new SparseRow(a2.Size + a1.Size); //based on https://stackoverflow.com/a/12993675/1106889 //result = a1 * a1Coef + a2 * a2Coef; var c1 = 0; var c2 = 0; var i1s = a1.Indexes; var v1s = a1.Values; var l1 = a1.Size; var i2s = a2.Indexes; var v2s = a2.Values; var l2 = a2.Size; while (c1 < l1 && c2 < l2) { var i1 = i1s[c1]; var i2 = i2s[c2]; var v1 = v1s[c1]; var v2 = v2s[c2]; if (i1 > i2) { buf.Add(i2 /*or i1*/, v2 * a2Coef); c2++; } else if (i1 < i2) { buf.Add(i1, v1 * a1Coef); c1++; } else {//common var newValue = v1 * a1Coef + v2 * a2Coef; buf.Add(i1, newValue); c1++; c2++; } } return(buf); }
public static SparseRow From(int[] columns, double[] values) { Array.Sort(columns, values); Array.Sort(columns); var buf = new SparseRow(); buf.Columns = new List <int>(columns); buf.Values = new List <double>(values); buf.NextMember = new List <int>(Enumerable.Range(0, columns.Length).Select(i => i + 1)); buf.NextMember[buf.NextMember.Count - 1] = -1; buf.Head = 0; return(buf); }
/// <summary> /// Adds the addition into the target /// </summary> /// <param name="target"></param> /// <param name="addition"></param> /// <param name="factor"></param> public static void Add(SparseRow target, SparseRow addition, double factor) { var it = target.Head; var ia = addition.Head; while (true) { var c1 = target.Columns[it]; var c2 = addition.Columns[ia]; while (c2 < c1) { } it = target.NextMember[it]; } throw new NotImplementedException(); }
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()); }
/// <summary> /// Eliminates the specified index of <see cref="eliminated"/> row by adding appropriated multiply of <see cref="eliminator"/> to it. /// </summary> /// <param name="eliminator">The eliminator row.</param> /// <param name="eliminated">The eliminated row.</param> /// <param name="eliminateIndex">The index of eliminated member.</param> /// <returns>Eliminated version of <see cref="eliminated"/></returns> public static SparseRow Eliminate(SparseRow eliminator, SparseRow eliminated, int eliminateIndex, double epsilon = 0) { var buf = new SparseRow(eliminated.Size + eliminator.Size); //based on https://stackoverflow.com/a/12993675/1106889 //result = eliminator * coef + eliminated double coef; { var t1 = Array.BinarySearch(eliminator.Indexes, 0, eliminator.Size, eliminateIndex); var t2 = Array.BinarySearch(eliminated.Indexes, 0, eliminated.Size, eliminateIndex); if (t1 < 0 || t2 < 0) { throw new Exception(); } coef = -eliminated.Values[t2] / eliminator.Values[t1]; } var c1 = 0; var c2 = 0; var i1s = eliminator.Indexes; var v1s = eliminator.Values; var l1 = eliminator.Size; var i2s = eliminated.Indexes; var v2s = eliminated.Values; var l2 = eliminated.Size; while (c1 < l1 && c2 < l2) { var i1 = i1s[c1]; var i2 = i2s[c2]; var v1 = v1s[c1]; var v2 = v2s[c2]; if (i1 > i2) { buf.Add(i2 /*or i1*/, v2); c2++; } else if (i1 < i2) { buf.Add(i1, v1 * coef); c1++; } else {//common if (i1 != i2) { throw new Exception(); } var newValue = v1 * coef + v2; if (i1 == eliminateIndex || Math.Abs(newValue) < epsilon) { //this is eliminated item, newValue should be zero and nothing to add if (Math.Abs(newValue) > 1e-6) { throw new Exception("wrong result"); } } else { buf.Add(i1, newValue); } c1++; c2++; } } //tail { for (; c1 < l1; c1++) { var i1 = i1s[c1]; var v1 = v1s[c1]; buf.Add(i1, v1 * coef); } for (; c2 < l2; c2++) { var i2 = i2s[c2]; var v2 = v2s[c2]; buf.Add(i2, v2); } } return(buf); }