1aaa7dc30SBarry Smith #include <../src/tao/unconstrained/impls/neldermead/neldermead.h> 2aaa7dc30SBarry Smith #include <petscvec.h> 3a7e14dcfSSatish Balay 440244768SBarry Smith /*------------------------------------------------------------*/ 5*d71ae5a4SJacob Faibussowitsch static PetscErrorCode NelderMeadSort(TAO_NelderMead *nm) 6*d71ae5a4SJacob Faibussowitsch { 740244768SBarry Smith PetscReal *values = nm->f_values; 840244768SBarry Smith PetscInt *indices = nm->indices; 940244768SBarry Smith PetscInt dim = nm->N + 1; 1040244768SBarry Smith PetscInt i, j, index; 1140244768SBarry Smith PetscReal val; 1240244768SBarry Smith 1340244768SBarry Smith PetscFunctionBegin; 1440244768SBarry Smith for (i = 1; i < dim; i++) { 1540244768SBarry Smith index = indices[i]; 1640244768SBarry Smith val = values[index]; 17ad540459SPierre Jolivet for (j = i - 1; j >= 0 && values[indices[j]] > val; j--) indices[j + 1] = indices[j]; 1840244768SBarry Smith indices[j + 1] = index; 1940244768SBarry Smith } 2040244768SBarry Smith PetscFunctionReturn(0); 2140244768SBarry Smith } 2240244768SBarry Smith 2340244768SBarry Smith /*------------------------------------------------------------*/ 24*d71ae5a4SJacob Faibussowitsch static PetscErrorCode NelderMeadReplace(TAO_NelderMead *nm, PetscInt index, Vec Xmu, PetscReal f) 25*d71ae5a4SJacob Faibussowitsch { 2640244768SBarry Smith PetscFunctionBegin; 2740244768SBarry Smith /* Add new vector's fraction of average */ 289566063dSJacob Faibussowitsch PetscCall(VecAXPY(nm->Xbar, nm->oneOverN, Xmu)); 299566063dSJacob Faibussowitsch PetscCall(VecCopy(Xmu, nm->simplex[index])); 3040244768SBarry Smith nm->f_values[index] = f; 3140244768SBarry Smith 329566063dSJacob Faibussowitsch PetscCall(NelderMeadSort(nm)); 3340244768SBarry Smith 3440244768SBarry Smith /* Subtract last vector from average */ 359566063dSJacob Faibussowitsch PetscCall(VecAXPY(nm->Xbar, -nm->oneOverN, nm->simplex[nm->indices[nm->N]])); 3640244768SBarry Smith PetscFunctionReturn(0); 3740244768SBarry Smith } 3840244768SBarry Smith 39a7e14dcfSSatish Balay /* ---------------------------------------------------------- */ 40*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_NM(Tao tao) 41*d71ae5a4SJacob Faibussowitsch { 42a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 4353506e15SBarry Smith PetscInt n; 44a7e14dcfSSatish Balay 45a7e14dcfSSatish Balay PetscFunctionBegin; 469566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->solution, &n)); 4753506e15SBarry Smith nm->N = n; 4853506e15SBarry Smith nm->oneOverN = 1.0 / n; 499566063dSJacob Faibussowitsch PetscCall(VecDuplicateVecs(tao->solution, nm->N + 1, &nm->simplex)); 509566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nm->N + 1, &nm->f_values)); 519566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nm->N + 1, &nm->indices)); 529566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &nm->Xbar)); 539566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &nm->Xmur)); 549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &nm->Xmue)); 559566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &nm->Xmuc)); 56a7e14dcfSSatish Balay 5783c8fe1dSLisandro Dalcin tao->gradient = NULL; 58a7e14dcfSSatish Balay tao->step = 0; 59a7e14dcfSSatish Balay PetscFunctionReturn(0); 60a7e14dcfSSatish Balay } 61a7e14dcfSSatish Balay 62a7e14dcfSSatish Balay /* ---------------------------------------------------------- */ 63*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_NM(Tao tao) 64*d71ae5a4SJacob Faibussowitsch { 65a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 6653506e15SBarry Smith 67a7e14dcfSSatish Balay PetscFunctionBegin; 68a7e14dcfSSatish Balay if (tao->setupcalled) { 699566063dSJacob Faibussowitsch PetscCall(VecDestroyVecs(nm->N + 1, &nm->simplex)); 709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&nm->Xmuc)); 719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&nm->Xmue)); 729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&nm->Xmur)); 739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&nm->Xbar)); 74a7e14dcfSSatish Balay } 759566063dSJacob Faibussowitsch PetscCall(PetscFree(nm->indices)); 769566063dSJacob Faibussowitsch PetscCall(PetscFree(nm->f_values)); 779566063dSJacob Faibussowitsch PetscCall(PetscFree(tao->data)); 78a7e14dcfSSatish Balay PetscFunctionReturn(0); 79a7e14dcfSSatish Balay } 80a7e14dcfSSatish Balay 81a7e14dcfSSatish Balay /*------------------------------------------------------------*/ 82*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_NM(Tao tao, PetscOptionItems *PetscOptionsObject) 83*d71ae5a4SJacob Faibussowitsch { 84a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 85a7e14dcfSSatish Balay 86a7e14dcfSSatish Balay PetscFunctionBegin; 87d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Nelder-Mead options"); 889566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_nm_lamda", "initial step length", "", nm->lamda, &nm->lamda, NULL)); 899566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_nm_mu", "mu", "", nm->mu_oc, &nm->mu_oc, NULL)); 90a7e14dcfSSatish Balay nm->mu_ic = -nm->mu_oc; 91a7e14dcfSSatish Balay nm->mu_r = nm->mu_oc * 2.0; 92a7e14dcfSSatish Balay nm->mu_e = nm->mu_oc * 4.0; 93d0609cedSBarry Smith PetscOptionsHeadEnd(); 94a7e14dcfSSatish Balay PetscFunctionReturn(0); 95a7e14dcfSSatish Balay } 96a7e14dcfSSatish Balay 97a7e14dcfSSatish Balay /*------------------------------------------------------------*/ 98*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_NM(Tao tao, PetscViewer viewer) 99*d71ae5a4SJacob Faibussowitsch { 100a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 101a7e14dcfSSatish Balay PetscBool isascii; 102a7e14dcfSSatish Balay 103a7e14dcfSSatish Balay PetscFunctionBegin; 1049566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 105a7e14dcfSSatish Balay if (isascii) { 1069566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 10763a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "expansions: %" PetscInt_FMT "\n", nm->nexpand)); 10863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "reflections: %" PetscInt_FMT "\n", nm->nreflect)); 10963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "inside contractions: %" PetscInt_FMT "\n", nm->nincontract)); 11063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "outside contractionss: %" PetscInt_FMT "\n", nm->noutcontract)); 11163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Shrink steps: %" PetscInt_FMT "\n", nm->nshrink)); 1129566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 113a7e14dcfSSatish Balay } 114a7e14dcfSSatish Balay PetscFunctionReturn(0); 115a7e14dcfSSatish Balay } 116a7e14dcfSSatish Balay 117a7e14dcfSSatish Balay /*------------------------------------------------------------*/ 118*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_NM(Tao tao) 119*d71ae5a4SJacob Faibussowitsch { 120a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 121a7e14dcfSSatish Balay PetscReal *x; 1228931d482SJason Sarich PetscInt i; 123a7e14dcfSSatish Balay Vec Xmur = nm->Xmur, Xmue = nm->Xmue, Xmuc = nm->Xmuc, Xbar = nm->Xbar; 124a7e14dcfSSatish Balay PetscReal fr, fe, fc; 125a7e14dcfSSatish Balay PetscInt shrink; 126a7e14dcfSSatish Balay PetscInt low, high; 127a7e14dcfSSatish Balay 128a7e14dcfSSatish Balay PetscFunctionBegin; 129a7e14dcfSSatish Balay nm->nshrink = 0; 130a7e14dcfSSatish Balay nm->nreflect = 0; 131a7e14dcfSSatish Balay nm->nincontract = 0; 132a7e14dcfSSatish Balay nm->noutcontract = 0; 133a7e14dcfSSatish Balay nm->nexpand = 0; 134a7e14dcfSSatish Balay 13548a46eb9SPierre Jolivet if (tao->XL || tao->XU || tao->ops->computebounds) PetscCall(PetscInfo(tao, "WARNING: Variable bounds have been set but will be ignored by NelderMead algorithm\n")); 136a7e14dcfSSatish Balay 1379566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, nm->simplex[0])); 1389566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, nm->simplex[0], &nm->f_values[0])); 139a7e14dcfSSatish Balay nm->indices[0] = 0; 140a7e14dcfSSatish Balay for (i = 1; i < nm->N + 1; i++) { 1419566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, nm->simplex[i])); 1429566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(nm->simplex[i], &low, &high)); 143a7e14dcfSSatish Balay if (i - 1 >= low && i - 1 < high) { 1449566063dSJacob Faibussowitsch PetscCall(VecGetArray(nm->simplex[i], &x)); 145a7e14dcfSSatish Balay x[i - 1 - low] += nm->lamda; 1469566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(nm->simplex[i], &x)); 147a7e14dcfSSatish Balay } 148a7e14dcfSSatish Balay 1499566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, nm->simplex[i], &nm->f_values[i])); 150a7e14dcfSSatish Balay nm->indices[i] = i; 151a7e14dcfSSatish Balay } 152a7e14dcfSSatish Balay 153a7e14dcfSSatish Balay /* Xbar = (Sum of all simplex vectors - worst vector)/N */ 1549566063dSJacob Faibussowitsch PetscCall(NelderMeadSort(nm)); 1559566063dSJacob Faibussowitsch PetscCall(VecSet(Xbar, 0.0)); 15648a46eb9SPierre Jolivet for (i = 0; i < nm->N; i++) PetscCall(VecAXPY(Xbar, 1.0, nm->simplex[nm->indices[i]])); 1579566063dSJacob Faibussowitsch PetscCall(VecScale(Xbar, nm->oneOverN)); 1583ecd9318SAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 159a7e14dcfSSatish Balay while (1) { 160e1e80dc8SAlp Dener /* Call general purpose update function */ 161dbbe0bcdSBarry Smith PetscTryTypeMethod(tao, update, tao->niter, tao->user_update); 162d643b47cSToby Isaac ++tao->niter; 163a7e14dcfSSatish Balay shrink = 0; 1649566063dSJacob Faibussowitsch PetscCall(VecCopy(nm->simplex[nm->indices[0]], tao->solution)); 1659566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, nm->f_values[nm->indices[0]], nm->f_values[nm->indices[nm->N]] - nm->f_values[nm->indices[0]], 0.0, tao->ksp_its)); 1669566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, nm->f_values[nm->indices[0]], nm->f_values[nm->indices[nm->N]] - nm->f_values[nm->indices[0]], 0.0, 1.0)); 167dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, convergencetest, tao->cnvP); 1683ecd9318SAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) break; 169a7e14dcfSSatish Balay 170a7e14dcfSSatish Balay /* x(mu) = (1 + mu)Xbar - mu*X_N+1 */ 1719566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmur, 1 + nm->mu_r, -nm->mu_r, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 1729566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmur, &fr)); 173a7e14dcfSSatish Balay 174a7e14dcfSSatish Balay if (nm->f_values[nm->indices[0]] <= fr && fr < nm->f_values[nm->indices[nm->N - 1]]) { 175a7e14dcfSSatish Balay /* reflect */ 176a7e14dcfSSatish Balay nm->nreflect++; 1779566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Reflect\n")); 1789566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmur, fr)); 17953506e15SBarry Smith } else if (fr < nm->f_values[nm->indices[0]]) { 180a7e14dcfSSatish Balay /* expand */ 181a7e14dcfSSatish Balay nm->nexpand++; 1829566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Expand\n")); 1839566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmue, 1 + nm->mu_e, -nm->mu_e, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 1849566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmue, &fe)); 185a7e14dcfSSatish Balay if (fe < fr) { 1869566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmue, fe)); 187a7e14dcfSSatish Balay } else { 1889566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmur, fr)); 189a7e14dcfSSatish Balay } 190a7e14dcfSSatish Balay } else if (nm->f_values[nm->indices[nm->N - 1]] <= fr && fr < nm->f_values[nm->indices[nm->N]]) { 191a7e14dcfSSatish Balay /* outside contraction */ 192a7e14dcfSSatish Balay nm->noutcontract++; 1939566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Outside Contraction\n")); 1949566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmuc, 1 + nm->mu_oc, -nm->mu_oc, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 195a7e14dcfSSatish Balay 1969566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmuc, &fc)); 197a7e14dcfSSatish Balay if (fc <= fr) { 1989566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmuc, fc)); 19953506e15SBarry Smith } else shrink = 1; 200a7e14dcfSSatish Balay } else { 201a7e14dcfSSatish Balay /* inside contraction */ 202a7e14dcfSSatish Balay nm->nincontract++; 2039566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Inside Contraction\n")); 2049566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmuc, 1 + nm->mu_ic, -nm->mu_ic, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 2059566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmuc, &fc)); 206a7e14dcfSSatish Balay if (fc < nm->f_values[nm->indices[nm->N]]) { 2079566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmuc, fc)); 20853506e15SBarry Smith } else shrink = 1; 209a7e14dcfSSatish Balay } 210a7e14dcfSSatish Balay 211a7e14dcfSSatish Balay if (shrink) { 212a7e14dcfSSatish Balay nm->nshrink++; 2139566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Shrink\n")); 214a7e14dcfSSatish Balay 215a7e14dcfSSatish Balay for (i = 1; i < nm->N + 1; i++) { 2169566063dSJacob Faibussowitsch PetscCall(VecAXPBY(nm->simplex[nm->indices[i]], 1.5, -0.5, nm->simplex[nm->indices[0]])); 2179566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, nm->simplex[nm->indices[i]], &nm->f_values[nm->indices[i]])); 218a7e14dcfSSatish Balay } 2199566063dSJacob Faibussowitsch PetscCall(VecAXPBY(Xbar, 1.5 * nm->oneOverN, -0.5, nm->simplex[nm->indices[0]])); 220a7e14dcfSSatish Balay 221a7e14dcfSSatish Balay /* Add last vector's fraction of average */ 2229566063dSJacob Faibussowitsch PetscCall(VecAXPY(Xbar, nm->oneOverN, nm->simplex[nm->indices[nm->N]])); 2239566063dSJacob Faibussowitsch PetscCall(NelderMeadSort(nm)); 224a7e14dcfSSatish Balay /* Subtract new last vector from average */ 2259566063dSJacob Faibussowitsch PetscCall(VecAXPY(Xbar, -nm->oneOverN, nm->simplex[nm->indices[nm->N]])); 226a7e14dcfSSatish Balay } 227a7e14dcfSSatish Balay } 228a7e14dcfSSatish Balay PetscFunctionReturn(0); 229a7e14dcfSSatish Balay } 230a7e14dcfSSatish Balay 231a7e14dcfSSatish Balay /* ---------------------------------------------------------- */ 2321eb8069cSJason Sarich /*MC 2331eb8069cSJason Sarich TAONM - Nelder-Mead solver for derivative free, unconstrained minimization 2341eb8069cSJason Sarich 2351eb8069cSJason Sarich Options Database Keys: 2361eb8069cSJason Sarich + -tao_nm_lamda - initial step length 237a2b725a8SWilliam Gropp - -tao_nm_mu - expansion/contraction factor 2381eb8069cSJason Sarich 2391eb8069cSJason Sarich Level: beginner 2401eb8069cSJason Sarich M*/ 2411eb8069cSJason Sarich 242*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_NM(Tao tao) 243*d71ae5a4SJacob Faibussowitsch { 244a7e14dcfSSatish Balay TAO_NelderMead *nm; 245a7e14dcfSSatish Balay 246a7e14dcfSSatish Balay PetscFunctionBegin; 2474dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&nm)); 248a7e14dcfSSatish Balay tao->data = (void *)nm; 249a7e14dcfSSatish Balay 250a7e14dcfSSatish Balay tao->ops->setup = TaoSetUp_NM; 251a7e14dcfSSatish Balay tao->ops->solve = TaoSolve_NM; 252a7e14dcfSSatish Balay tao->ops->view = TaoView_NM; 253a7e14dcfSSatish Balay tao->ops->setfromoptions = TaoSetFromOptions_NM; 254a7e14dcfSSatish Balay tao->ops->destroy = TaoDestroy_NM; 255a7e14dcfSSatish Balay 2566552cf8aSJason Sarich /* Override default settings (unless already changed) */ 2576552cf8aSJason Sarich if (!tao->max_it_changed) tao->max_it = 2000; 2586552cf8aSJason Sarich if (!tao->max_funcs_changed) tao->max_funcs = 4000; 259a7e14dcfSSatish Balay 26083c8fe1dSLisandro Dalcin nm->simplex = NULL; 261a7e14dcfSSatish Balay nm->lamda = 1; 262a7e14dcfSSatish Balay 263a7e14dcfSSatish Balay nm->mu_ic = -0.5; 264a7e14dcfSSatish Balay nm->mu_oc = 0.5; 265a7e14dcfSSatish Balay nm->mu_r = 1.0; 266a7e14dcfSSatish Balay nm->mu_e = 2.0; 267a7e14dcfSSatish Balay 268a7e14dcfSSatish Balay PetscFunctionReturn(0); 269a7e14dcfSSatish Balay } 270