Beispiel #1
0
        // Use homotopy method with newton's method to find a solution for F(x) = 0.
        private static List <Arrow> NSolve(List <Expression> F, List <Arrow> x0, double Epsilon, int MaxIterations)
        {
            int M = F.Count;
            int N = x0.Count;

            // Compute JxF, the Jacobian of F.
            List <Dictionary <Expression, Expression> > JxF = Jacobian(F, x0.Select(i => i.Left)).ToList();

            // Define a function to evaluate JxH(x), where H = F(x) - s*F(x0).
            CodeGen code = new CodeGen();

            ParamExpr _JxH = code.Decl <double[, ]>(Scope.Parameter, "JxH");
            ParamExpr _x0  = code.Decl <double[]>(Scope.Parameter, "x0");
            ParamExpr _s   = code.Decl <double>(Scope.Parameter, "s");

            // Load x_j from the input array and add them to the map.
            for (int j = 0; j < N; ++j)
            {
                code.DeclInit(x0[j].Left, LinqExpr.ArrayAccess(_x0, LinqExpr.Constant(j)));
            }

            LinqExpr error = code.Decl <double>("error");

            // Compile the expressions to assign JxH
            for (int i = 0; i < M; ++i)
            {
                LinqExpr _i = LinqExpr.Constant(i);
                for (int j = 0; j < N; ++j)
                {
                    code.Add(LinqExpr.Assign(
                                 LinqExpr.ArrayAccess(_JxH, _i, LinqExpr.Constant(j)),
                                 code.Compile(JxF[i][x0[j].Left])));
                }
                // e = F(x) - s*F(x0)
                LinqExpr e = code.DeclInit <double>("e", LinqExpr.Subtract(code.Compile(F[i]), LinqExpr.Multiply(LinqExpr.Constant((double)F[i].Evaluate(x0)), _s)));
                code.Add(LinqExpr.Assign(LinqExpr.ArrayAccess(_JxH, _i, LinqExpr.Constant(N)), e));
                // error += e * e
                code.Add(LinqExpr.AddAssign(error, LinqExpr.Multiply(e, e)));
            }

            // return error
            code.Return(error);

            Func <double[, ], double[], double, double> JxH = code.Build <Func <double[, ], double[], double, double> >().Compile();

            double[] x = new double[N];

            // Remember where we last succeeded/failed.
            double s0 = 0.0;
            double s1 = 1.0;

            do
            {
                try
                {
                    // H(F, s) = F - s*F0
                    NewtonsMethod(M, N, JxH, s0, x, Epsilon, MaxIterations);

                    // Success at this s!
                    s1 = s0;
                    for (int i = 0; i < N; ++i)
                    {
                        x0[i] = Arrow.New(x0[i].Left, x[i]);
                    }

                    // Go near the goal.
                    s0 = Lerp(s0, 0.0, 0.9);
                }
                catch (FailedToConvergeException)
                {
                    // Go near the last success.
                    s0 = Lerp(s0, s1, 0.9);

                    for (int i = 0; i < N; ++i)
                    {
                        x[i] = (double)x0[i].Right;
                    }
                }
            } while (s0 > 0.0 && s1 >= s0 + 1e-6);

            // Make sure the last solution is at F itself.
            if (s0 != 0.0)
            {
                NewtonsMethod(M, N, JxH, 0.0, x, Epsilon, MaxIterations);
                for (int i = 0; i < N; ++i)
                {
                    x0[i] = Arrow.New(x0[i].Left, x[i]);
                }
            }

            return(x0);
        }