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);
        }
Ejemplo n.º 2
0
        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++;
            }
        }