Beispiel #1
0
        // BFGF Minimizer
        public static Value Argmin(Value function, Value initial, Value tolerance, Netlist netlist, Style style, int s)
        {
            if (!(initial is ListValue <Value>))
            {
                throw new Error("argmin: expecting a list for second argument");
            }
            Vector <double> initialGuess = CreateVector.Dense((initial as ListValue <Value>).ToDoubleArray("argmin: expecting a list of numbers for second argument"));

            if (!(tolerance is NumberValue))
            {
                throw new Error("argmin: expecting a number for third argument");
            }
            double toler = (tolerance as NumberValue).value;

            if (!(function is FunctionValue))
            {
                throw new Error("argmin: expecting a function as first argument");
            }
            FunctionValue closure = function as FunctionValue;

            if (closure.parameters.parameters.Count != 1)
            {
                throw new Error("argmin: initial values and function parameters have different lengths");
            }

            IObjectiveFunction objectiveFunction = ObjectiveFunction.Gradient(
                (Vector <double> objParameters) => {
                const string badResult  = "argmin: objective function should return a list with a number (cost) and a list of numbers (partial derivatives of cost)";
                List <Value> parameters = new List <Value>(); foreach (double parameter in objParameters)
                {
                    parameters.Add(new NumberValue(parameter));
                }
                ListValue <Value> arg1 = new ListValue <Value>(parameters);
                List <Value> arguments = new List <Value>(); arguments.Add(arg1);
                bool autoContinue      = netlist.autoContinue; netlist.autoContinue = true;
                Value result           = closure.ApplyReject(arguments, netlist, style, s);
                if (result == null)
                {
                    throw new Error(badResult);
                }
                netlist.autoContinue = autoContinue;
                if (!(result is ListValue <Value>))
                {
                    throw new Error(badResult);
                }
                List <Value> results = (result as ListValue <Value>).elements;
                if (results.Count != 2 || !(results[0] is NumberValue) || !(results[1] is ListValue <Value>))
                {
                    throw new Error(badResult);
                }
                double cost = (results[0] as NumberValue).value;
                ListValue <Value> gradients = results[1] as ListValue <Value>;
                KGui.gui.GuiOutputAppendText("argmin: parameters=" + arg1.Format(style) + " => cost=" + style.FormatDouble(cost) + ", gradients=" + results[1].Format(style) + Environment.NewLine);
                return(new Tuple <double, Vector <double> >(cost, CreateVector.Dense(gradients.ToDoubleArray(badResult))));
            });

            try {
                BfgsMinimizer      minimizer = new BfgsMinimizer(toler, toler, toler);
                MinimizationResult result    = minimizer.FindMinimum(objectiveFunction, initialGuess);
                if (result.ReasonForExit == ExitCondition.Converged || result.ReasonForExit == ExitCondition.AbsoluteGradient || result.ReasonForExit == ExitCondition.RelativeGradient)
                {
                    List <Value> elements = new List <Value>();
                    for (int i = 0; i < result.MinimizingPoint.Count; i++)
                    {
                        elements.Add(new NumberValue(result.MinimizingPoint[i]));
                    }
                    ListValue <Value> list = new ListValue <Value>(elements);
                    KGui.gui.GuiOutputAppendText("argmin: converged with parameters " + list.Format(style) + " and reason '" + result.ReasonForExit + "'" + Environment.NewLine);
                    return(list);
                }
                else
                {
                    throw new Error("reason '" + result.ReasonForExit.ToString() + "'");
                }
            } catch (Exception e) { throw new Error("argmin ended: " + ((e.InnerException == null) ? e.Message : e.InnerException.Message)); } // somehow we need to recatch the inner exception coming from CostAndGradient
        }