/** * returns the OperationEval concrete impl instance corresponding * to the supplied operationPtg */ public static ValueEval Evaluate(OperationPtg ptg, ValueEval[] args, OperationEvaluationContext ec) { if (ptg == null) { throw new ArgumentException("ptg must not be null"); } Frame.Utils.NPOI.SS.Formula.Functions.Function result = _instancesByPtgClass[ptg] as Frame.Utils.NPOI.SS.Formula.Functions.Function; if (result != null) { return(result.Evaluate(args, ec.RowIndex, (short)ec.ColumnIndex)); } if (ptg is AbstractFunctionPtg) { AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg; int functionIndex = fptg.GetFunctionIndex(); switch (functionIndex) { case Frame.Utils.NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT: return(Indirect.instance.Evaluate(args, ec)); case Frame.Utils.NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL: return(UserDefinedFunction.instance.Evaluate(args, ec)); } return(FunctionEval.GetBasicFunction(functionIndex).Evaluate(args, ec.RowIndex, ec.ColumnIndex)); } throw new Exception("Unexpected operation ptg class (" + ptg.GetType().Name + ")"); }
// Change values in some range public void modify(SpreadSheetRange <AI1, AI2> range, FunctionEval <V> function) { // Using a delegate to change the values in a range! // Objective is to iterate in a range and apply a function to each // element in that range AI1 rmin = range.upperLeft.first; AI2 cmin = range.upperLeft.second; AI1 rmax = range.lowerRight.first; AI2 cmax = range.lowerRight.second; int Rmin = r[rmin]; int Rmax = r[rmax]; int Cmin = c[cmin]; int Cmax = c[cmax]; // Now must find the integer indices corresponding to these V d; for (int ri = Rmin; ri <= Rmax; ri++) { for (int ci = Cmin; ci <= Cmax; ci++) { d = mat[ri, ci]; function(ref d); mat[ri, ci] = d; } } }
/** * Return a collection of functions that POI can evaluate * * @return names of functions supported by POI */ public static IList <String> GetSupportedFunctionNames() { List <String> lst = new List <String>(); lst.AddRange(FunctionEval.GetSupportedFunctionNames()); lst.AddRange(AnalysisToolPak.GetSupportedFunctionNames()); return(lst.AsReadOnly()); }
/** * Return a collection of functions that POI does not support * * @return names of functions NOT supported by POI */ public static List <string> GetNotSupportedFunctionNames() { List <string> lst = new List <string>(); lst.AddRange(FunctionEval.GetNotSupportedFunctionNames()); lst.AddRange(AnalysisToolPak.GetNotSupportedFunctionNames()); return(lst); }
public void EvaluateTest2() { FunctionEval fe = new FunctionEval(); String s1 = "5*x^0"; double result = fe.Evaluate(s1, 5); Assert.AreEqual(5, result); }
public void EvaluateTest4() { FunctionEval fe = new FunctionEval(); String s1 = "2*3+7-1*1"; double result = fe.Evaluate(s1); Assert.AreEqual(2 * 3 + 7 - 1 * 1, result); }
public void EvaluateTest1() { FunctionEval fe = new FunctionEval(); String s1 = "2*3*x^0"; double result = fe.Evaluate(s1, 3); Assert.AreEqual(6, result); }
public void TestRegisterInRuntime() { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = (HSSFSheet)wb.CreateSheet("Sheet1"); HSSFRow row = (HSSFRow)sheet.CreateRow(0); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); HSSFCell cellA = (HSSFCell)row.CreateCell(0); cellA.CellFormula = ("FISHER(A5)"); CellValue cv; try { //NPOI //Run it twice in NUnit Gui Window, the first passed but the second failed. //Maybe the function was cached. Ignore it. cv = fe.Evaluate(cellA); Assert.Fail("expectecd exception"); } catch (NotImplementedException) { ; } FunctionEval.RegisterFunction("FISHER", new Function1());/*Function() { * public ValueEval Evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { * return ErrorEval.NA; * } * });*/ cv = fe.Evaluate(cellA); Assert.AreEqual(ErrorEval.NA.ErrorCode, cv.ErrorValue); HSSFCell cellB = (HSSFCell)row.CreateCell(1); cellB.CellFormula = ("CUBEMEMBERPROPERTY(A5)"); try { cv = fe.Evaluate(cellB); Assert.Fail("expectecd exception"); } catch (NotImplementedException) { ; } AnalysisToolPak.RegisterFunction("CUBEMEMBERPROPERTY", new FreeRefFunction1());/*FreeRefFunction() { * public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) { * return ErrorEval.NUM_ERROR; * } * });*/ cv = fe.Evaluate(cellB); Assert.AreEqual(ErrorEval.NUM_ERROR.ErrorCode, cv.ErrorValue); }
public void HeunTest() { double epsilon = .001; double expected = 4.0; FunctionEval fe = new FunctionEval(); double result = fe.Euler("2*x", 0, 0, 2); Boolean accurate = Math.Abs(result - expected) < epsilon; Assert.IsTrue(accurate); }
/** * returns the OperationEval concrete impl instance corresponding * to the supplied operationPtg */ public static ValueEval Evaluate(OperationPtg ptg, ValueEval[] args, OperationEvaluationContext ec) { if (ptg == null) { throw new ArgumentException("ptg must not be null"); } NPOI.SS.Formula.Functions.Function result = _instancesByPtgClass[ptg] as NPOI.SS.Formula.Functions.Function; FreeRefFunction udfFunc = null; if (result == null) { if (ptg is AbstractFunctionPtg) { AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg; int functionIndex = fptg.FunctionIndex; switch (functionIndex) { case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT: udfFunc = Indirect.instance; break; case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL: udfFunc = UserDefinedFunction.instance; break; default: result = FunctionEval.GetBasicFunction(functionIndex); break; } } } if (result != null) { if (result is ArrayFunction) { ArrayFunction func = (ArrayFunction)result; ValueEval eval = EvaluateArrayFunction(func, args, ec); if (eval != null) { return(eval); } } return(result.Evaluate(args, ec.RowIndex, (short)ec.ColumnIndex)); } else if (udfFunc != null) { return(udfFunc.Evaluate(args, ec)); } throw new Exception("Unexpected operation ptg class (" + ptg.GetType().Name + ")"); }
/** * @param startRowIndex row index in the spreadsheet where the first function/operator is found * @param TestFocusFunctionName name of a single function/operator to Test alone. * Typically pass <code>null</code> to Test all functions */ private void ProcessFunctionGroup(int startRowIndex, String testFocusFunctionName) { HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); ReadOnlyCollection <String> funcs = FunctionEval.GetSupportedFunctionNames(); int rowIndex = startRowIndex; while (true) { IRow r = sheet.GetRow(rowIndex); String targetFunctionName = GetTargetFunctionName(r); if (targetFunctionName == null) { throw new AssertionException("Test spreadsheet cell empty on row (" + (rowIndex + 1) + "). Expected function name or '" + SS.FUNCTION_NAMES_END_SENTINEL + "'"); } if (targetFunctionName.Equals(SS.FUNCTION_NAMES_END_SENTINEL)) { // found end of functions list break; } if (testFocusFunctionName == null || targetFunctionName.Equals(testFocusFunctionName, StringComparison.CurrentCultureIgnoreCase)) { // expected results are on the row below IRow expectedValuesRow = sheet.GetRow(rowIndex + 1); if (expectedValuesRow == null) { int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row throw new AssertionException("Missing expected values row for function '" + targetFunctionName + " (row " + missingRowNum + ")"); } switch (ProcessFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) { case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break; case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break; default: throw new SystemException("unexpected result"); case Result.NO_EVALUATIONS_FOUND: // do nothing String uname = targetFunctionName.ToUpper(); if (startRowIndex >= SS.START_FUNCTIONS_ROW_INDEX && funcs.Contains(uname)) { Debug.WriteLine(uname + ": function is supported but missing test data", ""); } break; } } rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION; } }
public static bool CheckDerivatives(FunctionEval func, double[] x0) { double eps = 1e-4; int K = x0.Length; var grad = Vector.Zero(K); var dummy = Vector.Zero(K); double f0 = func(Vector.FromArray(x0), ref grad); bool allGood = true; for (int i = 0; i < K; i++) { var x = x0.Select(j => j).ToArray(); double eps2 = eps * Math.Max(Math.Abs(x[i]), 0.1); x[i] += eps2; double f = func(Vector.FromArray(x), ref dummy); double fd = (f - f0) / eps2; Console.WriteLine("{2} Analytic gradient: {0} finite difference: {1}", grad[i], fd, i); } return(allGood); }
/// <summary> /// Check whether "func" correctly calculates derivatives /// </summary> /// <param name="func">Return the objective and calculates gradients</param> /// <param name="x0">The point to perform the check around</param> /// <returns>Whether the derivatives are correctly calculated. </returns> public static bool CheckDerivatives(FunctionEval func, Vector x0) { double eps = 1e-4; int K = x0.Count; var grad = Vector.Zero(K); Vector dummy = Vector.Zero(K); double f0 = func(x0, ref grad); bool allGood = true; for (int i = 0; i < K; i++) { var x = x0.Clone(); double eps2 = eps * System.Math.Max(System.Math.Abs(x[i]), 1e-8); x[i] += eps2; double f = func(x, ref dummy); double fd = (f - f0) / eps2; Console.WriteLine("{2} Analytic gradient: {0} finite difference: {1}", grad[i], fd, i); } return(allGood); }
/// <summary> /// Run an unconstrained minimization using BFGS /// </summary> /// <param name="x0">Starting step</param> /// <param name="normOfFirstStep">Norm of first step</param> /// <param name="func">Multivariate function and derivative evaluator</param> /// <returns>The local minimum point</returns> public virtual Vector Run(Vector x0, double normOfFirstStep, FunctionEval func) { dimension = x0.Count; currentX = Vector.Copy(x0); if (func == null) { throw new ArgumentException("Null function"); } cancel = false; // Initialize all the fields needed for optimisation feval = new FunctionEval(func); searchDir = Vector.Zero(dimension); currentDeriv = Vector.Zero(dimension); // Following vectors are the components of the // inverse Hessian update Vector S = Vector.Zero(dimension); Vector Y = Vector.Zero(dimension); Vector minusRhoS = Vector.Zero(dimension); Matrix EyeMinusSYt = new Matrix(dimension, dimension); Vector prevDeriv = Vector.Zero(dimension); PositiveDefiniteMatrix H = new PositiveDefiniteMatrix(dimension, dimension); H.SetToIdentity(); Matrix HWork = new Matrix(dimension, dimension); // Get the derivatives currentObj = feval(currentX, ref currentDeriv); double prevObj = currentObj; double rho; double step = 0.0; double step0 = initialStep; double convergenceCheck = double.MaxValue; double invDim = 1.0 / dimension; iter = 0; while (convergenceCheck > this.epsilon && !cancel) { prevDeriv.SetTo(currentDeriv); // Compute search direction searchDir.SetToProduct(H, currentDeriv); // Negate for (int i = 0; i < dimension; i++) { searchDir[i] = -searchDir[i]; } if (iter == 0) { double sdNorm = System.Math.Sqrt(searchDir.Inner(searchDir)); double sdMult = normOfFirstStep / sdNorm; searchDir.SetToProduct(searchDir, sdMult); for (int i = 0; i < dimension; i++) { H[i, i] = sdMult; } } //------------------------------------------------------ // Line search enforces strong Wolfe conditions // so curvature condition is guaranteed //------------------------------------------------------ step = TryLineSearch(step0, stepMax, currentDeriv.Inner(searchDir)); // Get the delta between the old and new point S.SetToProduct(searchDir, step); // Update the current point currentX.SetToSum(currentX, S); // Calculate the objective and the derivative at the new point //double objVal = feval(currentX, ref currentDeriv); // If the step is 0, break now, once we have re-evaluated the function and derivs. if (step == 0.0) { break; } // Difference of derivs Y.SetToDifference(currentDeriv, prevDeriv); // BFGS update rho = 1.0 / (S.Inner(Y)); if (iter == 0) { // Modify the Hessian to yTs/yTy times Identity double beta = S.Inner(S) * rho; for (int i = 0; i < dimension; i++) { H[i, i] = beta; } } EyeMinusSYt.SetToIdentity(); EyeMinusSYt.SetToSumWithOuter(EyeMinusSYt, -rho, S, Y); HWork.SetToProduct(EyeMinusSYt, H); H.SetToProduct(HWork, EyeMinusSYt.Transpose()); H.SetToSumWithOuter(H, rho, S, S); switch (convergenceCriteria) { case ConvergenceCriteria.Gradient: convergenceCheck = System.Math.Sqrt(invDim * currentDeriv.Inner(currentDeriv)); break; case ConvergenceCriteria.Objective: convergenceCheck = System.Math.Abs(prevObj - currentObj) / System.Math.Max(1, System.Math.Max(prevObj, currentObj)); break; } prevObj = currentObj; // Let anyone who's interested know that we have completed an iteration RaiseIterationEvent(iter, currentObj, convergenceCheck); if (++iter > maxIterations) { break; } } return(currentX); }
/// <summary> /// Run an unconstrained minimization using BFGS /// </summary> /// <param name="x0">Starting step</param> /// <param name="normOfFirstStep">Norm of first step</param> /// <param name="func">Multivariate function and derivative evaluator</param> /// <returns>The local minimum point</returns> public override Vector Run(Vector x0, double normOfFirstStep, FunctionEval func) { Init(); dimension = x0.Count; if (approxDim >= dimension) { return(base.Run(x0, normOfFirstStep, func)); } if (func == null) { throw new ArgumentException("Null function"); } cancel = false; // Initialize all the fields needed for optimisation feval = new FunctionEval(func); searchDir = Vector.Zero(dimension, sparsity: x0.Sparsity); currentX = Vector.Copy(x0); currentDeriv = Vector.Zero(dimension, sparsity: x0.Sparsity); // Following vectors are the components of the // inverse Hessian update Vector S = Vector.Zero(dimension, sparsity: x0.Sparsity); Vector Y = Vector.Zero(dimension, sparsity: x0.Sparsity); Vector q = Vector.Zero(dimension, sparsity: x0.Sparsity); Vector alpha = Vector.Zero(approxDim); Vector work = Vector.Zero(dimension, sparsity: x0.Sparsity); Vector prevDeriv = Vector.Zero(dimension, sparsity: x0.Sparsity); Vector H0 = Vector.Zero(dimension, sparsity: x0.Sparsity); // Get the derivatives currentObj = feval(currentX, ref currentDeriv); double beta; double prevObj = currentObj; double step = 0.0; double step0 = initialStep; double convergenceCheck = double.MaxValue; double invDim = 1.0 / dimension; iter = 0; while (convergenceCheck > this.epsilon && !cancel) { prevDeriv.SetTo(currentDeriv); // H0 = gamma x Identity if (iter == 0) { double sdNorm = System.Math.Sqrt(currentDeriv.Inner(currentDeriv)); H0.SetAllElementsTo(normOfFirstStep / sdNorm); } else { H0.SetAllElementsTo(ess[0].Inner(wye[0]) / wye[0].Inner(wye[0])); } //--------------------------------------------- // L-BFGS two loop recursion. Algorithm 7.4 in // Nocedal and Wright 2006 //--------------------------------------------- q.SetTo(currentDeriv); int cnt = ess.Count; for (int i = 0; i < cnt; i++) { alpha[i] = rho[i] * ess[i].Inner(q); work.SetToProduct(wye[i], alpha[i]); q.SetToDifference(q, work); } searchDir.SetToProduct(q, H0); for (int i = cnt - 1; i >= 0; i--) { beta = rho[i] * wye[i].Inner(searchDir); work.SetToProduct(ess[i], alpha[i] - beta); searchDir.SetToSum(searchDir, work); } // Negate searchDir.Scale(-1.0); //------------------------------------------------------ // Line search enforces strong Wolfe conditions // so curvature condition is guaranteed //------------------------------------------------------ step = TryLineSearch(step0, stepMax, currentDeriv.Inner(searchDir)); // Discard items falling off the bottom of the list if (cnt >= approxDim) { ess.RemoveAt(cnt - 1); wye.RemoveAt(cnt - 1); rho.RemoveAt(cnt - 1); } // we have done this calculation already... // Get the delta between the old and new point S.SetToProduct(searchDir, step); ess.Insert(0, Vector.Copy(S)); // Update the current point currentX.SetToSum(currentX, S); // Find the derivative at the new point // we should already have this //if (objVal != currentObj) // throw new InferRuntimeException("error"); // If the step is 0, break now, once we have re-evaluated the function and derivs. if (step == 0.0) { if (debug) { Console.WriteLine("Step size is 0.0, stopping LBFGS."); } break; } // Difference of derivs Y.SetToDifference(currentDeriv, prevDeriv); wye.Insert(0, Vector.Copy(Y)); // Rho rho.Insert(0, 1.0 / (S.Inner(Y))); // Value used for convergence switch (convergenceCriteria) { case ConvergenceCriteria.Gradient: convergenceCheck = System.Math.Sqrt(invDim * currentDeriv.Inner(currentDeriv)); break; case ConvergenceCriteria.Objective: convergenceCheck = System.Math.Abs(prevObj - currentObj) / System.Math.Max(1, System.Math.Max(prevObj, currentObj)); break; } prevObj = currentObj; // Let anyone who's interested know that we have completed an iteration RaiseIterationEvent(iter, currentObj, convergenceCheck); if (++iter > maxIterations) { if (debug) { Console.WriteLine("Max iterations reached, stopping LBFGS."); } break; } } return(currentX); }
/** * Register a function in runtime. * * @param name the function name * @param func the functoin to register * @throws IllegalArgumentException if the function is unknown or already registered. * @since 3.8 beta6 */ public static void RegisterFunction(string name, Functions.Function func) { FunctionEval.RegisterFunction(name, func); }
/** * @param startRowIndex row index in the spreadsheet where the first function/operator is found * @param testFocusFunctionName name of a single function/operator to test alone. * Typically pass <code>null</code> to test all functions */ private void ProcessFunctionGroup(int startRowIndex, string testFocusFunctionName) { HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); ReadOnlyCollection <string> funcs = FunctionEval.GetSupportedFunctionNames(); int rowIndex = startRowIndex; while (true) { IRow r = sheet.GetRow(rowIndex); // only Evaluate non empty row if (r != null) { string targetFunctionName = GetTargetFunctionName(r); string targetTestName = GetTargetTestName(r); if (targetFunctionName == null) { throw new AssertFailedException("Test spreadsheet cell empty on row (" + (rowIndex + 1) + "). Expected function name or '" + SS.FUNCTION_NAMES_END_SENTINEL + "'"); } if (targetFunctionName.Equals(SS.FUNCTION_NAMES_END_SENTINEL)) { // found end of functions list break; } if (testFocusFunctionName == null || targetFunctionName.Equals(testFocusFunctionName, StringComparison.CurrentCultureIgnoreCase)) { // expected results are on the row below ICell expectedValueCell = r.GetCell(SS.COLUMN_INDEX_EXPECTED_VALUE); if (expectedValueCell == null) { int missingRowNum = rowIndex + 1; throw new AssertFailedException("Missing expected values cell for function '" + targetFunctionName + ", test" + targetTestName + " (row " + missingRowNum + ")"); } switch (ProcessFunctionRow(evaluator, targetFunctionName, targetTestName, r, expectedValueCell)) { case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break; case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break; default: throw new Exception("unexpected result"); case Result.NO_EVALUATIONS_FOUND: // do nothing string uname = targetFunctionName.ToUpper(); if (startRowIndex >= SS.START_FUNCTIONS_ROW_INDEX && funcs.Contains(uname)) { logger.Log(POILogger.WARN, uname + ": function is supported but missing test data"); } break; } } } rowIndex++; } }
public void TestExceptions() { NPOI.SS.Formula.Functions.Function func = new Function2(); try { FunctionEval.RegisterFunction("SUM", func); Assert.Fail("expectecd exception"); } catch (ArgumentException e) { Assert.AreEqual("POI already implememts SUM" + ". You cannot override POI's implementations of Excel functions", e.Message); } try { FunctionEval.RegisterFunction("SUMXXX", func); Assert.Fail("expectecd exception"); } catch (ArgumentException e) { Assert.AreEqual("Unknown function: SUMXXX", e.Message); } try { FunctionEval.RegisterFunction("ISODD", func); Assert.Fail("expectecd exception"); } catch (ArgumentException e) { Assert.AreEqual("ISODD is a function from the Excel Analysis Toolpack. " + "Use AnalysisToolpack.RegisterFunction(String name, FreeRefFunction func) instead.", e.Message); } FreeRefFunction atpFunc = new FreeRefFunction2();/*FreeRefFunction() { * public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) { * return ErrorEval.NUM_ERROR; * } * };*/ try { AnalysisToolPak.RegisterFunction("ISODD", atpFunc); Assert.Fail("expectecd exception"); } catch (ArgumentException e) { Assert.AreEqual("POI already implememts ISODD" + ". You cannot override POI's implementations of Excel functions", e.Message); } try { AnalysisToolPak.RegisterFunction("ISODDXXX", atpFunc); Assert.Fail("expectecd exception"); } catch (ArgumentException e) { Assert.AreEqual("ISODDXXX is not a function from the Excel Analysis Toolpack.", e.Message); } try { AnalysisToolPak.RegisterFunction("SUM", atpFunc); Assert.Fail("expectecd exception"); } catch (ArgumentException e) { Assert.AreEqual("SUM is a built-in Excel function. " + "Use FunctoinEval.RegisterFunction(String name, Function func) instead.", e.Message); } }
/// <summary> /// Try to optimise the kernel parameters under the specified marginal likelihood function. Note that only /// one step is taken since this will be called within a VB algorithm so it is inefficient to run to /// convergence /// </summary> /// <param name="marginalLikelihoodFunction"></param> /// <param name="result">The resulting precision matrix (to be cached for efficiency)</param> public void Optimise(MarginalLikelihoodFunction marginalLikelihoodFunction, ref PositiveDefiniteMatrix result) { callsCounter++; if (callsCounter <= settings.iterationsBeforeOptimiseHypers || hypersToOptimise.Length == 0) { return; } var startingPoint = hypersToOptimise.Select(i => kernel[i]).ToArray(); switch (settings.solverMethod) { case Settings.SolverMethod.MySolver: if (hypersToOptimise.Length > 1) { throw new ApplicationException("MySolver cannot currently optimise in more than 1D, please use LBFGS or GradientDescent"); } Converter <double, double> f3 = ll => { kernel[hypersToOptimise[0]] = ll; var prec = Utils.GramMatrix(kernel, xData).Inverse(); return(marginalLikelihoodFunction(prec, null, null)); }; double maxLoc = My1DOptimiser(f3, kernel[hypersToOptimise[0]]); kernel[hypersToOptimise[0]] = maxLoc; //Console.WriteLine("ll {0}, likelihood went from {1} to {2}", kernel[0], f3(startingPoint[0]), f3(kernel[0])); result = Utils.GramMatrix(kernel, xData).Inverse(); return; case Settings.SolverMethod.GradientDescent: FunctionEval fgd = delegate(Vector hypers, ref Vector gradientVector) { PositiveDefiniteMatrix[] gradK = (gradientVector == null) ? null : System.Linq.Enumerable.Range(0, hypers.Count).Select(_ => new PositiveDefiniteMatrix(xData.Length, xData.Length)).ToArray(); var prec = GramPrecision(hypers.ToArray(), ref gradK); return(marginalLikelihoodFunction(prec, gradK, gradientVector)); }; Vector gradientVect = Vector.Zero(hypersToOptimise.Length), dummy = null; var startPointerVector = Vector.FromArray(startingPoint); // take a small step in the steepest ascent direction double f0 = fgd(startPointerVector, ref gradientVect); double eps = .1; var absg = Math.Sqrt(gradientVect.Sum(o => o * o)); var xnew = Vector.FromArray(startingPoint) + gradientVect * (eps / absg); // find the function value here double fnew = fgd(xnew, ref dummy); // use this to approximate the curvature under a quadratic assumption double m = (fnew - f0) / (eps * eps) - absg / eps; double fopt; if (m < -1e-2) // good, m negative implies we have a convex function! { // go to the minimum of our quadratic approximation double step = 1.0; var xopt = Vector.FromArray(startingPoint) - gradientVect * (step / (2.0 * m)); fopt = fgd(xopt, ref dummy); // keep back tracking until the function improves while (fopt < f0) { step *= .5; xopt = Vector.FromArray(startingPoint) - gradientVect * (step / (2.0 * m)); fopt = fgd(xopt, ref dummy); if (step < 1.0e-10) { throw new ApplicationException("step size was tiny"); } } } else { if (fnew <= f0) { Console.WriteLine("Seem to be at the minimum! Gradient=" + absg); return; } double step = 1.0; double stepVal = fnew; step *= 2.0; double nextStepVal = fgd(startPointerVector + gradientVect * (step * eps / absg), ref dummy); // keep going until marginal likelihood decreases while (nextStepVal > stepVal) { step *= 2.0; stepVal = nextStepVal; nextStepVal = fgd(startPointerVector + gradientVect * (step * eps / absg), ref dummy); if (step > 1e6) { throw new ApplicationException("Kernel hyperparameter optimisation diverged"); } } step /= 2.0; fopt = fgd(startPointerVector + gradientVect * (step * eps / absg), ref dummy); if (fopt < f0) { throw new ApplicationException("Kernel hyperparameter optimisation diverged"); } } result = Utils.GramMatrix(kernel, xData).Inverse(); Console.WriteLine("ll {0}, likelihood went from {1} to {2}", kernel[0], f0, fopt); if (double.IsNaN(fopt) || fopt < f0) { throw new ApplicationException(); } return; } throw new ApplicationException(); }