/// <summary>
        /// Minimize the function
        /// </summary>
        /// <param name="diffFunc">Function to minimize</param><param name="startingPoint">Starting point</param>
        /// <returns>
        /// The minimum
        /// </returns>
        public double[] Minimize(DiffFunc diffFunc, double[] startingPoint)
        {
            var solver = new CompactQuasiNewtonSolver();

            var length = startingPoint.Length;
            this.variables = new int[length];
            for (var index = 0; index < length; ++index)
            {
                solver.AddVariable(null, out this.variables[index]);
                solver.SetValue(this.variables[index], startingPoint[index]);
            }

            int vid;
            solver.AddRow(null, out vid);
            solver.AddGoal(vid, 0, true);
            solver.FunctionEvaluator = this.FunctionEvaluator;
            solver.GradientEvaluator = this.GradientEvaluator;

            this.func = diffFunc;
            this.curGradient = new double[length];
            this.curVariableVals = new double[length];

            var nonlinearSolution = solver.Solve(this.solverParams);

            var numArray = new double[length];
            for (var index = 0; index < length; ++index)
            {
                numArray[index] = nonlinearSolution.GetValue(this.variables[index]);
            }

            return numArray;
        }
        /// <summary>
        /// Minimize the function
        /// </summary>
        /// <param name="diffFunc">Function to minimize</param><param name="startingPoint">Starting point</param>
        /// <returns>
        /// The minimum
        /// </returns>
        public double[] Minimize(DiffFunc diffFunc, double[] startingPoint)
        {
            var solver = new CompactQuasiNewtonSolver();

            var length = startingPoint.Length;

            this.variables = new int[length];
            for (var index = 0; index < length; ++index)
            {
                solver.AddVariable(null, out this.variables[index]);
                solver.SetValue(this.variables[index], startingPoint[index]);
            }

            int vid;

            solver.AddRow(null, out vid);
            solver.AddGoal(vid, 0, true);
            solver.FunctionEvaluator = this.FunctionEvaluator;
            solver.GradientEvaluator = this.GradientEvaluator;

            this.func            = diffFunc;
            this.curGradient     = new double[length];
            this.curVariableVals = new double[length];

            var nonlinearSolution = solver.Solve(this.solverParams);

            var numArray = new double[length];

            for (var index = 0; index < length; ++index)
            {
                numArray[index] = nonlinearSolution.GetValue(this.variables[index]);
            }

            return(numArray);
        }
        public static void SolveSecondMultidimensionalVariant(int dimentions)
        {
            var solverParams = new CompactQuasiNewtonSolverParams();
            var solver       = new CompactQuasiNewtonSolver();
            int vidRow;

            int[] vidVariables = new int[dimentions];
            //add variables
            for (int i = 0; i < dimentions; i++)
            {
                solver.AddVariable(null, out vidVariables[i]);
            }
            //add a row and set it as the goal
            solver.AddRow(null, out vidRow);
            solver.AddGoal(vidRow, 0, true);
            solver.FunctionEvaluator = SecondRosenbrockVariantFunction;
            solver.GradientEvaluator = SecondRosenbrockVariantGradient;
            solver.Solve(solverParams);
            Console.WriteLine("=========Second, more complicated multidimensional variant of Rosenbrock==========");
            Console.WriteLine(solver.ToString());

            // This variant of Rosenbrock function has a local minima as well
            // around the point x = -1, 1, 1, .... (first dimension is around -1 and the rest are around 1)
            // If we start from around this local optima the solver will find and return it, and may not get
            // to the global optima
            solver.SetValue(vidVariables[0], -1);
            for (int i = 1; i < dimentions; i++)
            {
                solver.SetValue(vidVariables[i], 1);
            }
            //Solve the model
            solver.Solve(solverParams);
            Console.WriteLine("=========Second, more complicated multidimensional variant of Rosenbrock, trapped in local Minima==========");
            Console.WriteLine(solver.ToString());
        }
        public static void SolveRosenbrock()
        {
            var solverParams = new CompactQuasiNewtonSolverParams();
            CompactQuasiNewtonSolver solver = new CompactQuasiNewtonSolver();
            int vidRow, vidVariableX, vidVariableY;

            //add variables
            solver.AddVariable(key: null, vid: out vidVariableX);
            solver.AddVariable(key: null, vid: out vidVariableY);
            //add a row and set it as the goal
            solver.AddRow(key: null, vid: out vidRow);
            solver.AddGoal(vid: vidRow, pri: 0, minimize: true);
            solver.FunctionEvaluator = OriginalRosenbrockFunction;
            solver.GradientEvaluator = OriginalRosenbrockGradient;
            solver.Solve(solverParams);
            Console.WriteLine("=========Original Rosenbrock==========");
            Console.WriteLine(solver.ToString());
        }
        public static void SolveFirstMultidimensionalVariant(int dimentions)
        {
            var solverParams = new CompactQuasiNewtonSolverParams();
            var solver       = new CompactQuasiNewtonSolver();
            int vidRow;

            int[] vidVariables = new int[dimentions];
            //add variables
            for (int i = 0; i < dimentions; i++)
            {
                solver.AddVariable(null, out vidVariables[i]);
            }
            //add a row and set it as the goal
            solver.AddRow(null, out vidRow);
            solver.AddGoal(vidRow, 0, true);

            // let's try some non-default starting point
            for (int i = 0; i < dimentions; i++)
            {
                solver.SetValue(vidVariables[i], -10);
            }
            solver.FunctionEvaluator = FirstRosenbrockVariantFunction;
            solver.GradientEvaluator = FirstRosenbrockVariantGradient;
            //Solve the model
            solver.Solve(solverParams);
            Console.WriteLine("=========First multidimensional variant of Rosenbrock (many uncoupled 2D Rosenbrock problems)==========");
            Console.WriteLine(solver.ToString());

            // let's limit the number of iteration to 5 less than actually needed.
            // We might get close enough answer.
            solverParams.IterationLimit = solver.IterationCount - 5;
            // set the starting point again
            for (int i = 0; i < dimentions; i++)
            {
                solver.SetValue(vidVariables[i], -10);
            }

            //Solve the model
            solver.Solve(solverParams);
            Console.WriteLine("=========First multidimensional variant of Rosenbrock, MaxIteration exceeded==========");
            Console.WriteLine(solver.ToString());
        }