/** Get the full simplex of the current thread. This may be useful if the target function * wants to modify the simplex */ /* public List<double[]> getSimplex() { * return simpTable.get(Thread.currentThread()); * } */ /** One minimization run (including reinitializations of the simplex until the result is stable) */ private void minimizeOnce(double[] initialParams, double[] initialParamVariations, int seed) { Random random = new Random(seed); var simp = makeSimplex(initialParams, initialParamVariations, random); if (simp == null) { status = wasInitialized ? REINITIALIZATION_FAILURE : INITIALIZATION_FAILURE; return; } wasInitialized = true; if (startTime == 0) { startTime = Java.SystemCurrentTimeMillis(); } //if (io.binroot.regression.IJ.debugMode) showSimplex(simp, seed+" Initialized:"); int bestVertexNumber = minimize(simp); // first minimization double bestValueSoFar = value(simp[bestVertexNumber]); //reinitialize until converged or error/aborted (don't care about reinitialization failure in other thread) bool reinitialisationFailure = false; while (status == SUCCESS || status == REINITIALIZATION_FAILURE) { double[] paramVariations = makeNewParamVariations(simp, bestVertexNumber, initialParams, initialParamVariations); if (!reInitializeSimplex(simp, bestVertexNumber, paramVariations, random)) { reinitialisationFailure = true; break; } //if (io.binroot.regression.IJ.debugMode) showSimplex(simp, seed+" Reinitialized:"); bestVertexNumber = minimize(simp); // minimize with reinitialized simplex if (belowErrorLimit(value(simp[bestVertexNumber]), bestValueSoFar, 2.0)) { break; } bestValueSoFar = value(simp[bestVertexNumber]); } if (reinitialisationFailure) { status = REINITIALIZATION_FAILURE; } else if (status == SUCCESS || status == REINITIALIZATION_FAILURE) //i.e. not aborted, not max iterations exceeded { numCompletedMinimizations++; // it was a complete minimization } //if (io.binroot.regression.IJ.debugMode) showSimplex(simp, seed+" Final:"); if (resultsVector != null) { lock (resultsVector) { resultsVector.Add(simp[bestVertexNumber]); } } else { result = simp[bestVertexNumber]; } }
/** Minimizes the target function by variation of the simplex. * Note that one call to this function never does more than 0.4*maxIter iterations. * @return index of the best value in simp */ private int minimize(List <double[]> simp) { int[] worstNextBestArray = new int[3]; // used to pass these indices from 'order' function double[] center = new double[numParams + 1 + numExtraArrayElements]; // center of all vertices except worst double[] reflected = new double[numParams + 1 + numExtraArrayElements]; // the 1st new vertex to try double[] secondTry = new double[numParams + 1 + numExtraArrayElements]; // expanded or contracted vertex order(simp, worstNextBestArray); int worst = worstNextBestArray[WORST]; int nextWorst = worstNextBestArray[NEXT_WORST]; int best = worstNextBestArray[BEST]; //showSimplex(simp, "before minimization, value="+value(simp[best])); //String operation="ini"; int thisNumIter = 0; while (true) { totalNumIter++; // global count over all threads thisNumIter++; // local count for this minimize call // THE MINIMIZAION ALGORITHM IS HERE { getCenter(simp, worst, center); // centroid of vertices except worst // Reflect worst vertex through centriod of not-worst getVertexAndEvaluate(center, simp[worst], -C_REFLECTION, reflected); if (value(reflected) <= value(simp[best])) // if it's better than the best... // try expanding it { getVertexAndEvaluate(center, simp[worst], -C_EXPANSION, secondTry); if (value(secondTry) <= value(reflected)) { copyVertex(secondTry, simp[worst]); // if expanded is better than reflected, keep it //operation="expa"; goto iteration; } } if (value(reflected) < value(simp[nextWorst])) { copyVertex(reflected, simp[worst]); // keep reflected if better than 2nd worst //operation="refl"; goto iteration; } else if (value(reflected) < value(simp[worst])) { // try outer contraction getVertexAndEvaluate(center, simp[worst], -C_CONTRACTION, secondTry); if (value(secondTry) <= value(reflected)) { copyVertex(secondTry, simp[worst]); // keep outer contraction //operation="outC"; goto iteration; } } else if (value(reflected) > value(simp[worst]) || double.IsNaN(value(reflected))) { // else inner contraction getVertexAndEvaluate(center, simp[worst], C_CONTRACTION, secondTry); if (value(secondTry) < value(simp[worst])) { copyVertex(secondTry, simp[worst]); // keep contracted if better than 2nd worst //operation="innC"; goto iteration; } } // if everything else has failed, contract simplex in on best shrinkSimplexAndEvaluate(simp, best); //operation="shri"; goto iteration; } // iteration: iteration: bool checkParamResolution = // if new 'worst' is not close to 'best', don't check any further paramResolutions != null && belowResolutionLimit(simp[worst], simp[best]); order(simp, worstNextBestArray); worst = worstNextBestArray[WORST]; nextWorst = worstNextBestArray[NEXT_WORST]; best = worstNextBestArray[BEST]; if (checkParamResolution) { if (belowResolutionLimit(simp, best)) // check whether all parameters are within the resolution limit { break; } } if (belowErrorLimit(value(simp[best]), value(simp[worst]), 4.0)) // make sure we are at the minimum: { getCenter(simp, -1, secondTry); // check center of the simplex evaluate(secondTry); if (value(secondTry) < value(simp[best])) { copyVertex(secondTry, simp[best]); // better than best: keep } } if (belowErrorLimit(value(simp[best]), value(simp[worst]), 4.0)) // no large spread of values { break; // looks like we are at the minimum } if (totalNumIter > maxIter || thisNumIter > 4 * (maxIter / 10)) { status = MAX_ITERATIONS_EXCEEDED; } if (status != SUCCESS) { break; } if ((ijStatusString != null || checkEscape) && totalNumIter > nextIterationForStatus) { long time = Java.SystemCurrentTimeMillis(); nextIterationForStatus = totalNumIter + (int)(totalNumIter * 500L / (time - startTime + 1)); //next display 0.5 sec later } } //showSimplex(simp, "after "+totalNumIter+" iterations: value="+value(simp[best])); return(best); }