/** * Determines whether a restart with a smaller simplex should be tried or not * * @return <CODE>true</CODE> if restart can be tried, <CODE>false</CODE> otherwise */ protected boolean restartCriterion() { double f, S1, S2; double[] fX = new double[dimXP1]; for (int i = 0; i < dimXP1; i++) fX[i] = x[i].getF(0); S1 = LinAlg.twoNorm(fX); S1 *= S1; S2 = LinAlg.oneNorm(fX); S2 *= S2; S2 /= (double) (dimXP1); f = (S1 - S2) / (double) dimX; if (f < (sqEps)) return true; else return false; }
/** * Runs the optimization process until a termination criteria is satisfied * * @param x0 initial point * @return <CODE>-1</CODE> if the maximum number of iteration is exceeded <br> * <CODE>+1</CODE> if the required accuracy is reached * @exception Exception * @exception OptimizerException */ public int run(Point x0) throws OptimizerException, Exception { boolean restart = false; int retFla = 0; int i, j, nue; int w = 0; int b = 0; double ssf = 1; int dimF = getDimensionF(); Point[] xkP1 = new Point[dimXP1]; // xkP1 = x(k+1) for (i = 0; i < dimXP1; i++) xkP1[i] = new Point(dimX, 0, dimF); Point xN = new Point(dimX, 0, dimF); Point xNN = new Point(dimX, 0, dimF); double[] xC = new double[dimX]; double[] xTemp = new double[dimX]; String[] com = new String[11]; com[1] = "Establish initial simplex (1)."; com[2] = "Reflection (2)."; com[4] = "Expansion (4)."; com[5] = "Partial outside contraction (5)."; com[6] = "Partial inside contraction (6)."; com[7] = "Total contraction to best known point (7)."; com[10] = "Invoke simplex reconstruction (10)."; final String comBesNowPoi = "Best known point in total contraction (7)."; final String comNewSte = "New step."; final String comBasPoi = "Base point for optimality check."; double[] dNew = new double[dimX]; // new movement direction of changed point double[] dOld = new double[dimX]; // old movement direction of changed point double dNewL2; // L2norm of dNew int stepOld = 0; // number of last step section double cosMov = -1; // inner product of the last two directions boolean insideContraction = false; // flag whether we have just a inside contraction // beyond us int step = 0; // number of step boolean tryRes; boolean iterate = true; int nexAllRes = konvge; // number of main iteration when next restart might // be enabled // Perturber for check of the optimaltity condition Perturber per = new Perturber(this); LinAlg.initialize(xC, 0); // optimization loop do { switch (step) { case 0: // Initalization for (i = 0; i < dimX; i++) // starting point x[0].setX(i, getX0(i)); step = 1; break; case 1: // Etablish the initial simplex for (i = 1; i < dimXP1; i++) { for (j = 0; j < dimX; j++) { // getX is used on x[0] since x[0] may be reassigned after a failed // optimality check if (i == j + 1) x[i].setX(j, x[0].getX(j) + ssf * getDx(j, x[0].getX(j))); else x[i].setX(j, x[0].getX(j)); } } // get the objective function values for the initial simplex if (restart) { i = 1; // first point is already known from step 10 restart = false; } else i = 0; for (; i < dimXP1; i++) { x[i].setComment(com[1]); x[i] = getF(x[i]); report(x[i], SUBITERATION); if (i == 0) report(x[i], MAINITERATION); checkObjectiveFunctionValue(x[i]); } step = 2; break; case 2: // determine worst and best point for the normal reflection w = getWorst(); b = getBest(); xC = getXCenter(w); xN.setComment(com[2]); xN.setX(reflect(xC, x[w].getX())); xN = getF(xN); report(xN, SUBITERATION); stepOld = step; step = (xN.getF(0) < x[b].getF(0)) ? 4 : 3; break; case 3: // compare trial with other vertices nue = dimXP1 - rank(xN.getF(0)); // if nue is 0, we got the worst point if (nue == 0) // we got even a worser point than we had step = 6; else if (nue == 1) // we got a worse point but not that worse as the last was step = 5; else // we got a good point { xkP1[w] = (Point) xN.clone(); step = 8; } break; case 4: // Expansion (try if further expansion of point is successfull) xNN.setComment(com[4]); xNN.setX(LinAlg.subtract(LinAlg.multiply(2., xN.getX()), xC)); xNN = getF(xNN); report(xNN, SUBITERATION); if (xNN.getF(0) < x[b].getF(0)) xkP1[w] = (Point) xNN.clone(); // expansion was successful else xkP1[w] = (Point) xN.clone(); stepOld = step; step = 8; break; case 5: // Partial outside contraction xNN.setComment(com[5]); xNN.setX(LinAlg.multiply(0.5, LinAlg.add(xC, xN.getX()))); xNN = getF(xNN); report(xNN, SUBITERATION); if (xNN.getF(0) <= xN.getF(0)) { xkP1[w] = (Point) xNN.clone(); stepOld = step; step = 8; } else step = 7; break; case 6: // Partial inside contraction xNN.setComment(com[6]); xNN.setX(LinAlg.multiply(0.5, LinAlg.add(xC, x[w].getX()))); xNN = getF(xNN); report(xNN, SUBITERATION); /* the inequality (fNN >= fX[w]) is changed so that we get a total contraction if some vertices are in a null space. Nelder Mead have in their paper (1965) the strict inequality (fNN > fX[w]) 02/16/99 wm */ if (xNN.getF(0) >= x[w].getF(0)) step = 7; else { xkP1[w] = (Point) xNN.clone(); stepOld = step; step = 8; insideContraction = true; } break; case 7: // Total contraction to best point // construct new simplex xkP1[b] = (Point) x[b].clone(); xkP1[b].setComment(comBesNowPoi); report(xkP1[b], SUBITERATION); report(xkP1[b], MAINITERATION); xTemp = x[b].getX(); for (i = 0; i < dimXP1; i++) { if (i != b) { xkP1[i].setComment(com[7]); xkP1[i].setX(LinAlg.multiply(0.5, LinAlg.add(xTemp, x[i].getX()))); xkP1[i] = getF(xkP1[i]); report(xkP1[i], SUBITERATION); report(xkP1[i], MAINITERATION); checkObjectiveFunctionValue(xkP1[i]); } } insideContraction = true; step = 9; break; case 8: // normal iteration loop for (i = 0; i < dimXP1; i++) { if (i != w) xkP1[i] = (Point) x[i].clone(); else { xkP1[w].setComment(com[stepOld]); report(xkP1[w], MAINITERATION); checkObjectiveFunctionValue(xkP1[w]); } } step = 9; break; case 9: // Termination criterion // increase k <- k+1 // Note: 9 is only entered from 7 or 8 // determine movement direction of simplex if (modStoCri) { System.arraycopy(dNew, 0, dOld, 0, dimX); // new (current) search direction double[][] temp1 = new double[dimXP1][dimX]; double[][] temp2 = new double[dimXP1][dimX]; for (i = 0; i < dimXP1; i++) { temp1[i] = xkP1[i].getX(); temp2[i] = x[i].getX(); } dNew = LinAlg.subtract(LinAlg.getCenter(temp1), LinAlg.getCenter(temp2)); dNewL2 = LinAlg.twoNorm(dNew); if (dNewL2 > Double.MIN_VALUE) dNew = LinAlg.multiply(1 / dNewL2, dNew); cosMov = LinAlg.innerProduct(dOld, dNew); } /////////////////////////////////////////////////////////// // update points for (i = 0; i < dimXP1; i++) x[i] = (Point) xkP1[i].clone(); if (checkMaxIteration()) { retFla = -1; iterate = false; break; } // check for restart if (modStoCri) tryRes = (insideContraction && (cosMov <= 0) && (nexAllRes <= getMainIterationNumber()) && restartCriterion()); else tryRes = (nexAllRes <= getMainIterationNumber()) && restartCriterion(); if (tryRes) { // try a restart step = 10; nexAllRes = getMainIterationNumber() + konvge + 1; } else { // do a usual iteration loop if (writeStepNumber()) { // get the best point b = getBest(); x[b].setComment(comNewSte); x[b] = increaseStepNumber(x[b]); report(x[b], MAINITERATION); report(x[b], SUBITERATION); } step = 2; } // reset contraction flag insideContraction = false; break; case 10: // restart test (note that w points to the new vertex) ssf = cFactor; // factor for step size b = getBest(); x[b].setComment(comBasPoi); report(x[b], SUBITERATION); per.perturb(x[b], ssf); if (per.gotOptimum()) { // we are at the minimum retFla = 1; reportMinimum(); iterate = false; } else { restart = true; // to prevent a recalculation of the 0-th pt. x[0] = per.getOptimalPoint(); x[0].setComment(com[10]); report(x[0], MAINITERATION); if (writeStepNumber()) { x[0].setComment(comNewSte); x[0] = increaseStepNumber(x[0]); report(x[0], MAINITERATION); } step = 1; } break; } } while (iterate); return retFla; }