public DulmageMendelsohn Generate(EquationSystem problem) { var A = CSparseWrapper.ConvertSparsityJacobian(problem); var dm = DulmageMendelsohn.Generate(A, 1); A.PermuteRows(dm.p); A.PermuteColumns(dm.q); //foreach (var value in A.EnumerateIndexed()) //{ // sw.WriteLine("{0},{1}", value.Item1, value.Item2); //} StringBuilder sb = new StringBuilder(); sb.AppendLine("Coarse Structure"); sb.AppendLine("Underdetermined : "); sb.AppendLine("Determined : "); sb.AppendLine("Overdetermined : "); sb.AppendLine("Fine Structure"); for (int i = dm.Blocks - 1; i >= 0; i--) { sb.AppendLine(String.Format("Block {0}: V {1} - {2} E {3} - {4}", i, dm.s[i], dm.s[i + 1] - 1, dm.r[i], dm.r[i + 1] - 1)); var varcount = dm.s[i + 1] - dm.s[i]; for (int j = 0; j < varcount; j++) { var vari = dm.q[dm.s[i] + j]; sb.Append(problem.Variables[vari] + ", "); } var eqcount = dm.r[i + 1] - dm.r[i]; for (int j = 0; j < eqcount; j++) { var vari = dm.p[dm.r[i] + j]; // sb.Append(problem.Constraints[vari] + ", "); } sb.AppendLine(""); } // Console.WriteLine((sb.ToString())); return(dm); }
public void Solve(EquationSystem system) { if (!SuppressLogging) { Log(String.Format("{0} {1,15} {2,15} {3,7} {4}", "Iter", "Step Length", "Infeasibility", "Damping", "Algorithm")); } if (!system.IsSquare()) { Status = "Newton-Solver can only solve square problems."; IsAborted = true; IsConverged = false; return; } ProblemData = system; ProblemData.CreateIndex(); ProblemData.GenerateJacobian(); Evaluator eval = new Evaluator(); _watch = System.Diagnostics.Stopwatch.StartNew(); var algorithm = "Newton"; var status = false; var scalingLogSum = new MatrixScalingLogSum(2); double[] U = null, V = null; Iterations = 0; IsConverged = false; IsAborted = false; double varNorm = 0; double eqNorm = 0; Vector delta = new Vector(system.NumberOfVariables); var lambda = BrakeFactor; for (int i = 0; i < system.NumberOfVariables; i++) { delta[i] = system.Variables[i].ValueInSI; } while (!IsConverged && !IsAborted) { string flags = ""; #region Jacobian and Residuals eval.Reset(); var b = CSparseWrapper.FillResiduals(system, eval); var A = CSparseWrapper.FillJacobian(system, eval); #endregion varNorm = delta.GetNorm(); eqNorm = 0;// string debugString = ""; for (int i = 0; i < b.Size; i++) { var babs = Math.Abs(b[i]); if (babs > eqNorm) { eqNorm = babs; if (DebugMode) { debugString = ProblemData.Equations[i].ToString(); } } } //b.ToDouble().Max((s) => Math.Abs(s)); //if(DebugMode) //debugString= ProblemData.Equations.Max(eq=> Math.Abs(eq.Residual())) if (!SuppressLogging) { Log(String.Format(" {0:000} {1,15} {2,15} {3,7} {4,4} {5} {6} {7}", Iterations, varNorm.ToString("G2", CultureInfo.InvariantCulture), eqNorm.ToString("G8", CultureInfo.InvariantCulture), lambda, "NEWTON", algorithm, flags, debugString)); } OnIteration?.Invoke(system); CheckAbortionCriteria(Iterations, MaximumIterations, eqNorm, Tolerance); if (IsAborted || IsConverged) { break; } #region Scaling //TODO: Only rescale when necessary? Maybe decide based on condition number? // Current version only scales once at the beginning. if (ScalingFrequency == MatrixScalingFrequency.Once && (U == null || V == null) || ScalingFrequency == MatrixScalingFrequency.Always) { scalingLogSum.GetMatrixScalingFactors(A, out U, out V); } if (DoScaling) { for (int i = 0; i < system.NumberOfEquations; i++) { b[i] = b[i] * U[i]; } var UM = CSparseWrapper.CreateDiagonal(system.NumberOfEquations, U); var VM = CSparseWrapper.CreateDiagonal(system.NumberOfEquations, V); A = UM.Multiply(A); A = A.Multiply(VM); } #endregion delta = CSparseWrapper.SolveLinearSystem(A, delta, -b, out status, out algorithm); #region Scaling 2 if (DoScaling) { for (int i = 0; i < delta.Size; i++) { delta[i] = delta[i] * V[i]; } } #endregion lambda = BrakeFactor; if (delta.GetNorm() > _maximumNewtonStep) { //LogWarning("Variable step above limit. Truncating Newton step"); flags += "T"; delta /= delta.GetNorm() / _maximumNewtonStep; } else { flags += "_"; } if (status == false) { LogWarning("Error during factorization. Performing steepest descent step"); //delta = new Vector(system.NumberOfVariables, 1e-6); //Force rescaling when now direction could be found if (ScalingFrequency == MatrixScalingFrequency.OnDemand) { U = null; V = null; } flags += "D"; lambda *= 0.1; A.TransposeMultiply((-b).ToDouble(), delta.ToDouble()); } else { flags += "_"; } Func <Vector, Double> FuncLineSearch = ((r) => r.ToDouble().Max(s => Math.Abs(s))); var F0 = FuncLineSearch(b); var x0 = system.Variables.Select(v => v.ValueInSI).ToArray(); var lineSearchIter = 0; var currentStepLength = lambda; var lambdaMin = _lambdaMin; if (DoLinesearch) { while (lineSearchIter < 10) { for (int i = 0; i < delta.Size; i++) { var vari = system.Variables[i]; vari.ValueInSI = x0[i]; } ApplyNewtonStep(system, lambda, delta); eval.Reset(); b = CSparseWrapper.FillResiduals(system, eval); if (DoScaling) { for (int i = 0; i < system.NumberOfEquations; i++) { b[i] = b[i] * U[i]; } } var F1 = FuncLineSearch(b); if (F1 >= F0) { lambda *= 0.5; if (lambda < lambdaMin) { lambda = lambdaMin; } currentStepLength = lambda; if (!flags.Contains("L")) { flags += "L"; } } else { if (!flags.Contains("L")) { flags += "_"; } currentStepLength = lambda; break; } lineSearchIter++; } } else { flags += "_"; ApplyNewtonStep(system, lambda, delta); } Iterations++; } }