public virtual double[] Minimize(IDiffFunction dFunction, double functionTolerance, double[] initial, int maxIterations) { // check for derivatives int dimension = dFunction.DomainDimension(); //lastXx = 1.0; // evaluate function double fp = dFunction.ValueAt(initial); double[] xi = CopyArray(dFunction.DerivativeAt(initial)); // make some vectors double[] g = new double[dimension]; double[] h = new double[dimension]; double[] p = new double[dimension]; for (int j = 0; j < dimension; j++) { g[j] = -xi[j]; xi[j] = g[j]; h[j] = g[j]; p[j] = initial[j]; } // iterations bool simpleGDStep = false; for (int iterations = 1; iterations < maxIterations; iterations++) { if (!silent) { log.Info("Iter " + iterations + ' '); } // do a line min along descent direction //log.info("Minimizing from ("+p[0]+","+p[1]+") along ("+xi[0]+","+xi[1]+")\n"); //log.info("Current is "+fp); double[] p2 = LineMinimize(dFunction, p, xi); double fp2 = dFunction.ValueAt(p2); //log.info("Result is "+fp2+" (from "+fp+") at ("+p2[0]+","+p2[1]+")\n"); //log.info(fp2+"|"+(int)(Math.log((fabs(fp2-fp)+1e-100)/(fabs(fp)+fabs(fp2)+1e-100))/Math.log(10))); if (!silent) { System.Console.Error.Printf(" %s (delta: %s)\n", nf.Format(fp2), nf.Format(fp - fp2)); } if (monitor != null) { double monitorReturn = monitor.ValueAt(p2); if (monitorReturn < functionTolerance) { return(p2); } } // check convergence if (2.0 * Fabs(fp2 - fp) <= functionTolerance * (Fabs(fp2) + Fabs(fp) + Eps)) { // convergence if (!checkSimpleGDConvergence || simpleGDStep || simpleGD) { return(p2); } simpleGDStep = true; } else { //log.info("Switched to GD for a step."); //if (!simpleGD) //log.info("Switching to CGD."); simpleGDStep = false; } // shift variables for (int j_1 = 0; j_1 < dimension; j_1++) { xi[j_1] = p2[j_1] - p[j_1]; p[j_1] = p2[j_1]; } fp = fp2; // find the new gradient xi = CopyArray(dFunction.DerivativeAt(p)); if (iterationCallbackFunction != null) { iterationCallbackFunction.Callback(p2, iterations, fp2, xi); } //log.info("mx "+arrayMax(xi)+" mn "+arrayMin(xi)); if (!simpleGDStep && !simpleGD && (iterations % resetFrequency != 0)) { // do the magic -- part i // (calculate some dot products we'll need) double dgg = 0.0; double gg = 0.0; for (int j_2 = 0; j_2 < dimension; j_2++) { // g dot g gg += g[j_2] * g[j_2]; // grad dot grad // FR method is: // dgg += x[j]*x[j]; // PR method is: dgg += (xi[j_2] + g[j_2]) * xi[j_2]; } // check for miraculous convergence if (gg == 0.0) { return(p); } // magic part ii // (update the sequence in a way that tries to preserve conjugacy) double gam = dgg / gg; for (int j_3 = 0; j_3 < dimension; j_3++) { g[j_3] = -xi[j_3]; h[j_3] = g[j_3] + gam * h[j_3]; xi[j_3] = h[j_3]; } } else { // miraculous simpleGD convergence double xixi = 0.0; for (int j_2 = 0; j_2 < dimension; j_2++) { xixi += xi[j_2] * xi[j_2]; } // reset cgd for (int j_3 = 0; j_3 < dimension; j_3++) { g[j_3] = -xi[j_3]; xi[j_3] = g[j_3]; h[j_3] = g[j_3]; } if (xixi == 0.0) { return(p); } } } // too many iterations log.Info("Warning: exiting minimize because ITER exceeded!"); return(p); }