Actual source code: neldermead.c

  1: #include "neldermead.h"


  4: int NelderMeadSort(TAO_NelderMead *nm);
  5: int NelderMeadReplace(TAO_NelderMead *nm, int index, TaoVec *Xmu, double f);
  6: /* ---------------------------------------------------------- */
  9: int TaoSetUp_NelderMead(TAO_SOLVER tao, void *solver)
 10: {
 11:   TAO_NelderMead *nm = (TAO_NelderMead *)solver;
 12:   int info;
 13:   int size;
 14:   TaoVec *X;

 16:   TaoFunctionBegin;

 18:   
 19:   info = TaoGetSolution(tao,&X); CHKERRQ(info);
 20:   info = X->GetDimension(&size); CHKERRQ(info);
 21:   nm->N = size;
 22:   nm->oneOverN = 1.0/size;
 23:   info = X->CloneVecs(nm->N+1,&nm->simplex);
 24:   nm->f_values = new double[nm->N+1];
 25:   nm->indices =new int[nm->N+1];
 26:   info = X->Clone(&nm->Xbar); CHKERRQ(info);
 27:   info = X->Clone(&nm->Xmur); CHKERRQ(info);
 28:   info = X->Clone(&nm->Xmue); CHKERRQ(info);
 29:   info = X->Clone(&nm->Xmuc); CHKERRQ(info);
 30:   info = TaoSetLagrangianGradientVector(tao,0);CHKERRQ(info);
 31:   info = TaoSetStepDirectionVector(tao,0);CHKERRQ(info);

 33:   TaoFunctionReturn(0);
 34: }

 36: /* ---------------------------------------------------------- */
 39: int TaoSetDown_NelderMead(TAO_SOLVER tao, void *solver)
 40: {
 41:   TAO_NelderMead *nm = (TAO_NelderMead*)solver;
 42:   int info;
 43:   int i;
 44:   TaoFunctionBegin;
 45:   for (i=0;i<nm->N+1;i++) {
 46:     TaoVecDestroy( nm->simplex[i]);
 47:   }
 48:   delete [] nm->simplex;

 50:   info = TaoVecDestroy(nm->Xmuc); CHKERRQ(info);
 51:   info = TaoVecDestroy(nm->Xmue); CHKERRQ(info);
 52:   info = TaoVecDestroy(nm->Xmur); CHKERRQ(info);
 53:   info = TaoVecDestroy(nm->Xbar); CHKERRQ(info);
 54:   
 55:   delete [] nm->indices;
 56:   delete [] nm->f_values;
 57:   TaoFunctionReturn(0);
 58: }

 60: /*------------------------------------------------------------*/
 63: int TaoSetOptions_NelderMead(TAO_SOLVER tao, void *solver)
 64: {
 65:   
 66:   TAO_NelderMead *nm = (TAO_NelderMead*)solver;
 67:   int info;
 68:   
 69:   TaoFunctionBegin;
 70:   info = TaoOptionsHead("Nelder-Mead options"); CHKERRQ(info);
 71:   info = TaoOptionDouble("-tao_nm_lamda","initial step length","",
 72:                          nm->lamda,&nm->lamda,0); CHKERRQ(info);
 73:   info = TaoOptionDouble("-tao_nm_mu","mu","",nm->mu_oc,&nm->mu_oc,0); CHKERRQ(info);
 74:   nm->mu_ic = -nm->mu_oc;
 75:   nm->mu_r = nm->mu_oc*2.0;
 76:   nm->mu_e = nm->mu_oc*4.0;

 78:   info = TaoOptionsTail(); CHKERRQ(info);
 79:   TaoFunctionReturn(0);
 80: }

 82: /*------------------------------------------------------------*/
 85: int TaoView_NelderMead(TAO_SOLVER tao, void *solver)
 86: {
 87:   //int info;

 89:   TaoFunctionBegin;
 90:   TaoFunctionReturn(0);
 91: }

 93: /*------------------------------------------------------------*/
 96: int TaoSolve_NelderMead(TAO_SOLVER tao, void *solver)
 97: {
 98:   int info;
 99:   TAO_NelderMead *nm = (TAO_NelderMead*)solver;
100:   TaoTerminateReason reason;
101:   TaoVec *xx;
102:   double *x;
103:   int dim;
104:   double step=0.0;
105:   int iter=0,i;
106:   TaoVec *Xmur=nm->Xmur, *Xmue=nm->Xmue, *Xmuc=nm->Xmuc, *Xbar=nm->Xbar;
107:   double fr,fe,fc;
108:   int shrink;
109:   
110:   
111:   TaoFunctionBegin;
112:   info = TaoGetSolution(tao,&xx); CHKERRQ(info);
113:   for (i=0;i<nm->N+1;i++){
114:     info = nm->simplex[i]->CopyFrom(xx); CHKERRQ(info);
115:     if (i<nm->N) {
116:       info = nm->simplex[i]->GetArray(&x,&dim); CHKERRQ(info);
117:       x[i] += nm->lamda;
118:       info = nm->simplex[i]->RestoreArray(&x,&dim); CHKERRQ(info);
119:     }
120:     info = TaoComputeMeritFunction(tao,nm->simplex[i],&nm->f_values[i]); CHKERRQ(info);
121:     nm->indices[i] = i;
122:   }

124:   // Xbar  = (Sum of all simplex vectors - worst vector)/N
125:   info = NelderMeadSort(nm); CHKERRQ(info);
126:   info = Xbar->SetToZero(); CHKERRQ(info);
127:   for (i=0;i<nm->N;i++) {
128:     info = Xbar->Axpy(1.0,nm->simplex[nm->indices[i]]);
129:   }
130:   info = Xbar->Scale(nm->oneOverN);

132:   while (1) {
133:     shrink = 0;
134:     info = xx->CopyFrom(nm->simplex[nm->indices[0]]); CHKERRQ(info);
135:     info = TaoMonitor(tao,iter++,nm->f_values[nm->indices[0]],nm->f_values[nm->indices[nm->N]]-nm->f_values[nm->indices[0]],0,step,&reason); CHKERRQ(info);
136:     if (reason != TAO_CONTINUE_ITERATING) break;

138:     
139:     
140:     //x(mu) = (1 + mu)Xbar - mu*X_N+1
141:     info = Xmur->Waxpby(1+nm->mu_r,Xbar,-nm->mu_r,
142:                        nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
143:     info = TaoComputeMeritFunction(tao,Xmur,&fr); CHKERRQ(info);


146:     if (nm->f_values[nm->indices[0]] <= fr && fr < nm->f_values[nm->indices[nm->N-1]]) {
147:       // reflect
148:       info = PetscInfo(0,"Reflect\n"); CHKERRQ(info);
149:       info = NelderMeadReplace(nm,nm->indices[nm->N],Xmur,fr); CHKERRQ(info);
150:     }

152:     else if (fr < nm->f_values[nm->indices[0]]) {
153:       // expand
154:       info = PetscInfo(0,"Expand\n"); CHKERRQ(info);
155:       info = Xmue->Waxpby(1+nm->mu_e,Xbar,-nm->mu_e,
156:                           nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
157:       info = TaoComputeMeritFunction(tao,Xmue,&fe); CHKERRQ(info);
158:       if (fe < fr) {
159:         info = NelderMeadReplace(nm,nm->indices[nm->N],Xmue,fe); CHKERRQ(info);
160:       } else {
161:         info = NelderMeadReplace(nm,nm->indices[nm->N],Xmur,fr); CHKERRQ(info);
162:       }

164:     } else if (nm->f_values[nm->indices[nm->N-1]] <= fr && fr < nm->f_values[nm->indices[nm->N]]) {
165:       //outside contraction
166:       info = PetscInfo(0,"Outside Contraction\n"); CHKERRQ(info);
167:       info = Xmuc->Waxpby(1+nm->mu_oc,Xbar,-nm->mu_oc,
168:                           nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
169:       info = TaoComputeMeritFunction(tao,Xmuc,&fc); CHKERRQ(info);
170:       if (fc <= fr) {
171:         info = NelderMeadReplace(nm,nm->indices[nm->N],Xmuc,fc); CHKERRQ(info);
172:       }        else 
173:         shrink=1;
174:     } else {
175:       //inside contraction
176:       info = PetscInfo(0,"Inside Contraction\n"); CHKERRQ(info);
177:       info = Xmuc->Waxpby(1+nm->mu_ic,Xbar,-nm->mu_ic,
178:                           nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
179:       info = TaoComputeMeritFunction(tao,Xmuc,&fc); CHKERRQ(info);
180:       if (fc < nm->f_values[nm->indices[nm->N]]) {
181:         info = NelderMeadReplace(nm,nm->indices[nm->N],Xmuc,fc); CHKERRQ(info);
182:       } else
183:         shrink = 1;
184:     }

186:     if (shrink) {
187:       info = PetscInfo(0,"Shrink\n"); CHKERRQ(info);
188:       for (i=1;i<nm->N+1;i++) {
189:         info = nm->simplex[nm->indices[i]]->Axpby(1.5,nm->simplex[nm->indices[0]],-.5); CHKERRQ(info);
190:         info = TaoComputeMeritFunction(tao,nm->simplex[nm->indices[i]],
191:                                  &nm->f_values[nm->indices[i]]); CHKERRQ(info);
192:       }

194:       info = Xbar->Axpby(1.5*nm->oneOverN,nm->simplex[nm->indices[0]],-0.5); CHKERRQ(info);
195:       // Add last vector's fraction of average
196:       info = nm->Xbar->Axpy(nm->oneOverN,
197:                             nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
198:       info = NelderMeadSort(nm);
199:       // Subtract new last vector from average
200:       info = nm->Xbar->Axpy(-nm->oneOverN,
201:                             nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
202:     }

204:     
205:   }
206:   TaoFunctionReturn(0);
207: }

209: /* ---------------------------------------------------------- */
213: int TaoCreate_NelderMead(TAO_SOLVER tao)
214: {
215:   TAO_NelderMead *nm;
216:   int info;

218:   TaoFunctionBegin;
219:   info = TaoNew(TAO_NelderMead,&nm); CHKERRQ(info);

221:   info = PetscLogObjectMemory(tao,sizeof(TAO_NelderMead)); CHKERRQ(info);

223:   info = TaoSetTaoSolveRoutine(tao,TaoSolve_NelderMead,(void*)nm); CHKERRQ(info);
224:   info = TaoSetTaoSetUpDownRoutines(tao,TaoSetUp_NelderMead, 
225:                                     TaoSetDown_NelderMead); CHKERRQ(info);
226:   info = TaoSetTaoOptionsRoutine(tao,TaoSetOptions_NelderMead); CHKERRQ(info);
227:   info = TaoSetTaoViewRoutine(tao, TaoView_NelderMead); CHKERRQ(info);
228:   info = TaoSetMaximumIterates(tao,2000); CHKERRQ(info);
229:   info = TaoSetMaximumFunctionEvaluations(tao,4000); CHKERRQ(info);
230:   info = TaoSetTolerances(tao,1e-8,1e-8,0,0); CHKERRQ(info);


233:   nm->simplex = 0;
234:   nm->lamda = 1;

236:   nm->mu_ic = -0.5;
237:   nm->mu_oc = 0.5;
238:   nm->mu_r = 1.0;
239:   nm->mu_e = 2.0;

241:   TaoFunctionReturn(0);
242: }
244:     

246: /*------------------------------------------------------------*/
249: int NelderMeadSort(TAO_NelderMead *nm) {
250:   double *values = nm->f_values;
251:   int *indices = nm->indices;
252:   int dim = nm->N+1;

254:   int i,j,index;
255:   double val;
256:   TaoFunctionBegin;  
257:   for (i=1;i<dim;i++) {
258:     index = indices[i];
259:     val = values[index];
260:     for (j=i-1; j>=0 && values[indices[j]] > val; j--) {
261:       indices[j+1] = indices[j];
262:     }
263:     indices[j+1] = index;
264:   }  
265:   TaoFunctionReturn(0);
266: }


269: /*------------------------------------------------------------*/
272: int NelderMeadReplace(TAO_NelderMead *nm, int index, TaoVec *Xmu, double f)
273: {
274:   int info;
275:   TaoFunctionBegin;
276:   // Add new vector's fraction of average
277:   info = nm->Xbar->Axpy(nm->oneOverN,Xmu); CHKERRQ(info);
278:   info = nm->simplex[index]->CopyFrom(Xmu); CHKERRQ(info);
279:   nm->f_values[index] = f;

281:   info = NelderMeadSort(nm);
282:   // Subtract last vector from average
283:   info = nm->Xbar->Axpy(-nm->oneOverN,
284:                         nm->simplex[nm->indices[nm->N]]); CHKERRQ(info);
285:   TaoFunctionReturn(0);
286: }