1aaa7dc30SBarry Smith #include <../src/tao/unconstrained/impls/neldermead/neldermead.h> 2aaa7dc30SBarry Smith #include <petscvec.h> 3a7e14dcfSSatish Balay 440244768SBarry Smith /*------------------------------------------------------------*/ 5d71ae5a4SJacob Faibussowitsch static PetscErrorCode NelderMeadSort(TAO_NelderMead *nm) 6d71ae5a4SJacob 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 } 203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2140244768SBarry Smith } 2240244768SBarry Smith 2340244768SBarry Smith /*------------------------------------------------------------*/ 24d71ae5a4SJacob Faibussowitsch static PetscErrorCode NelderMeadReplace(TAO_NelderMead *nm, PetscInt index, Vec Xmu, PetscReal f) 25d71ae5a4SJacob 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]])); 363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3740244768SBarry Smith } 3840244768SBarry Smith 39a7e14dcfSSatish Balay /* ---------------------------------------------------------- */ 40d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_NM(Tao tao) 41d71ae5a4SJacob 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; 593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 60a7e14dcfSSatish Balay } 61a7e14dcfSSatish Balay 62a7e14dcfSSatish Balay /* ---------------------------------------------------------- */ 63d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_NM(Tao tao) 64d71ae5a4SJacob 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)); 783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 79a7e14dcfSSatish Balay } 80a7e14dcfSSatish Balay 81a7e14dcfSSatish Balay /*------------------------------------------------------------*/ 82ce78bad3SBarry Smith static PetscErrorCode TaoSetFromOptions_NM(Tao tao, PetscOptionItems PetscOptionsObject) 83d71ae5a4SJacob Faibussowitsch { 84a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 85a7e14dcfSSatish Balay 86a7e14dcfSSatish Balay PetscFunctionBegin; 87d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Nelder-Mead options"); 88a8d3b578SPierre Jolivet PetscCall(PetscOptionsDeprecated("-tao_nm_lamda", "-tao_nm_lambda", "3.18.4", NULL)); 89a8d3b578SPierre Jolivet PetscCall(PetscOptionsReal("-tao_nm_lambda", "initial step length", "", nm->lambda, &nm->lambda, NULL)); 909566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_nm_mu", "mu", "", nm->mu_oc, &nm->mu_oc, NULL)); 91a7e14dcfSSatish Balay nm->mu_ic = -nm->mu_oc; 92a7e14dcfSSatish Balay nm->mu_r = nm->mu_oc * 2.0; 93a7e14dcfSSatish Balay nm->mu_e = nm->mu_oc * 4.0; 94d0609cedSBarry Smith PetscOptionsHeadEnd(); 953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 96a7e14dcfSSatish Balay } 97a7e14dcfSSatish Balay 98a7e14dcfSSatish Balay /*------------------------------------------------------------*/ 99d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_NM(Tao tao, PetscViewer viewer) 100d71ae5a4SJacob Faibussowitsch { 101a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 102a7e14dcfSSatish Balay PetscBool isascii; 103a7e14dcfSSatish Balay 104a7e14dcfSSatish Balay PetscFunctionBegin; 1059566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 106a7e14dcfSSatish Balay if (isascii) { 1079566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 10863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "expansions: %" PetscInt_FMT "\n", nm->nexpand)); 10963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "reflections: %" PetscInt_FMT "\n", nm->nreflect)); 11063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "inside contractions: %" PetscInt_FMT "\n", nm->nincontract)); 11163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "outside contractionss: %" PetscInt_FMT "\n", nm->noutcontract)); 11263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Shrink steps: %" PetscInt_FMT "\n", nm->nshrink)); 1139566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 114a7e14dcfSSatish Balay } 1153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 116a7e14dcfSSatish Balay } 117a7e14dcfSSatish Balay 118a7e14dcfSSatish Balay /*------------------------------------------------------------*/ 119d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_NM(Tao tao) 120d71ae5a4SJacob Faibussowitsch { 121a7e14dcfSSatish Balay TAO_NelderMead *nm = (TAO_NelderMead *)tao->data; 122a7e14dcfSSatish Balay PetscReal *x; 1238931d482SJason Sarich PetscInt i; 124a7e14dcfSSatish Balay Vec Xmur = nm->Xmur, Xmue = nm->Xmue, Xmuc = nm->Xmuc, Xbar = nm->Xbar; 125a7e14dcfSSatish Balay PetscReal fr, fe, fc; 126a7e14dcfSSatish Balay PetscInt shrink; 127a7e14dcfSSatish Balay PetscInt low, high; 128a7e14dcfSSatish Balay 129a7e14dcfSSatish Balay PetscFunctionBegin; 130a7e14dcfSSatish Balay nm->nshrink = 0; 131a7e14dcfSSatish Balay nm->nreflect = 0; 132a7e14dcfSSatish Balay nm->nincontract = 0; 133a7e14dcfSSatish Balay nm->noutcontract = 0; 134a7e14dcfSSatish Balay nm->nexpand = 0; 135a7e14dcfSSatish Balay 13648a46eb9SPierre 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")); 137a7e14dcfSSatish Balay 1389566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, nm->simplex[0])); 1399566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, nm->simplex[0], &nm->f_values[0])); 140a7e14dcfSSatish Balay nm->indices[0] = 0; 141a7e14dcfSSatish Balay for (i = 1; i < nm->N + 1; i++) { 1429566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, nm->simplex[i])); 1439566063dSJacob Faibussowitsch PetscCall(VecGetOwnershipRange(nm->simplex[i], &low, &high)); 144a7e14dcfSSatish Balay if (i - 1 >= low && i - 1 < high) { 1459566063dSJacob Faibussowitsch PetscCall(VecGetArray(nm->simplex[i], &x)); 146a8d3b578SPierre Jolivet x[i - 1 - low] += nm->lambda; 1479566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(nm->simplex[i], &x)); 148a7e14dcfSSatish Balay } 149a7e14dcfSSatish Balay 1509566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, nm->simplex[i], &nm->f_values[i])); 151a7e14dcfSSatish Balay nm->indices[i] = i; 152a7e14dcfSSatish Balay } 153a7e14dcfSSatish Balay 154a7e14dcfSSatish Balay /* Xbar = (Sum of all simplex vectors - worst vector)/N */ 1559566063dSJacob Faibussowitsch PetscCall(NelderMeadSort(nm)); 1569566063dSJacob Faibussowitsch PetscCall(VecSet(Xbar, 0.0)); 15748a46eb9SPierre Jolivet for (i = 0; i < nm->N; i++) PetscCall(VecAXPY(Xbar, 1.0, nm->simplex[nm->indices[i]])); 1589566063dSJacob Faibussowitsch PetscCall(VecScale(Xbar, nm->oneOverN)); 1593ecd9318SAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 160a7e14dcfSSatish Balay while (1) { 161e1e80dc8SAlp Dener /* Call general purpose update function */ 162dbbe0bcdSBarry Smith PetscTryTypeMethod(tao, update, tao->niter, tao->user_update); 163d643b47cSToby Isaac ++tao->niter; 164a7e14dcfSSatish Balay shrink = 0; 1659566063dSJacob Faibussowitsch PetscCall(VecCopy(nm->simplex[nm->indices[0]], tao->solution)); 1669566063dSJacob 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)); 1679566063dSJacob 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)); 168dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, convergencetest, tao->cnvP); 1693ecd9318SAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) break; 170a7e14dcfSSatish Balay 171a7e14dcfSSatish Balay /* x(mu) = (1 + mu)Xbar - mu*X_N+1 */ 1729566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmur, 1 + nm->mu_r, -nm->mu_r, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 1739566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmur, &fr)); 174a7e14dcfSSatish Balay 175a7e14dcfSSatish Balay if (nm->f_values[nm->indices[0]] <= fr && fr < nm->f_values[nm->indices[nm->N - 1]]) { 176a7e14dcfSSatish Balay /* reflect */ 177a7e14dcfSSatish Balay nm->nreflect++; 1789566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Reflect\n")); 1799566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmur, fr)); 18053506e15SBarry Smith } else if (fr < nm->f_values[nm->indices[0]]) { 181a7e14dcfSSatish Balay /* expand */ 182a7e14dcfSSatish Balay nm->nexpand++; 1839566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Expand\n")); 1849566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmue, 1 + nm->mu_e, -nm->mu_e, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 1859566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmue, &fe)); 186a7e14dcfSSatish Balay if (fe < fr) { 1879566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmue, fe)); 188a7e14dcfSSatish Balay } else { 1899566063dSJacob Faibussowitsch PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmur, fr)); 190a7e14dcfSSatish Balay } 191a7e14dcfSSatish Balay } else if (nm->f_values[nm->indices[nm->N - 1]] <= fr && fr < nm->f_values[nm->indices[nm->N]]) { 192a7e14dcfSSatish Balay /* outside contraction */ 193a7e14dcfSSatish Balay nm->noutcontract++; 1949566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Outside Contraction\n")); 1959566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(Xmuc, 1 + nm->mu_oc, -nm->mu_oc, 0, Xbar, nm->simplex[nm->indices[nm->N]])); 196a7e14dcfSSatish Balay 1979566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, Xmuc, &fc)); 198*ac530a7eSPierre Jolivet if (fc <= fr) PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmuc, fc)); 199*ac530a7eSPierre Jolivet 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)); 206*ac530a7eSPierre Jolivet if (fc < nm->f_values[nm->indices[nm->N]]) PetscCall(NelderMeadReplace(nm, nm->indices[nm->N], Xmuc, fc)); 207*ac530a7eSPierre Jolivet else shrink = 1; 208a7e14dcfSSatish Balay } 209a7e14dcfSSatish Balay 210a7e14dcfSSatish Balay if (shrink) { 211a7e14dcfSSatish Balay nm->nshrink++; 2129566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Shrink\n")); 213a7e14dcfSSatish Balay 214a7e14dcfSSatish Balay for (i = 1; i < nm->N + 1; i++) { 2159566063dSJacob Faibussowitsch PetscCall(VecAXPBY(nm->simplex[nm->indices[i]], 1.5, -0.5, nm->simplex[nm->indices[0]])); 2169566063dSJacob Faibussowitsch PetscCall(TaoComputeObjective(tao, nm->simplex[nm->indices[i]], &nm->f_values[nm->indices[i]])); 217a7e14dcfSSatish Balay } 2189566063dSJacob Faibussowitsch PetscCall(VecAXPBY(Xbar, 1.5 * nm->oneOverN, -0.5, nm->simplex[nm->indices[0]])); 219a7e14dcfSSatish Balay 220a7e14dcfSSatish Balay /* Add last vector's fraction of average */ 2219566063dSJacob Faibussowitsch PetscCall(VecAXPY(Xbar, nm->oneOverN, nm->simplex[nm->indices[nm->N]])); 2229566063dSJacob Faibussowitsch PetscCall(NelderMeadSort(nm)); 223a7e14dcfSSatish Balay /* Subtract new last vector from average */ 2249566063dSJacob Faibussowitsch PetscCall(VecAXPY(Xbar, -nm->oneOverN, nm->simplex[nm->indices[nm->N]])); 225a7e14dcfSSatish Balay } 226a7e14dcfSSatish Balay } 2273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 228a7e14dcfSSatish Balay } 229a7e14dcfSSatish Balay 230a7e14dcfSSatish Balay /* ---------------------------------------------------------- */ 2311eb8069cSJason Sarich /*MC 2321eb8069cSJason Sarich TAONM - Nelder-Mead solver for derivative free, unconstrained minimization 2331eb8069cSJason Sarich 2341eb8069cSJason Sarich Options Database Keys: 235a8d3b578SPierre Jolivet + -tao_nm_lambda - initial step length 236a2b725a8SWilliam Gropp - -tao_nm_mu - expansion/contraction factor 2371eb8069cSJason Sarich 2381eb8069cSJason Sarich Level: beginner 2391eb8069cSJason Sarich M*/ 2401eb8069cSJason Sarich 241d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_NM(Tao tao) 242d71ae5a4SJacob Faibussowitsch { 243a7e14dcfSSatish Balay TAO_NelderMead *nm; 244a7e14dcfSSatish Balay 245a7e14dcfSSatish Balay PetscFunctionBegin; 2464dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&nm)); 247a7e14dcfSSatish Balay tao->data = (void *)nm; 248a7e14dcfSSatish Balay 249a7e14dcfSSatish Balay tao->ops->setup = TaoSetUp_NM; 250a7e14dcfSSatish Balay tao->ops->solve = TaoSolve_NM; 251a7e14dcfSSatish Balay tao->ops->view = TaoView_NM; 252a7e14dcfSSatish Balay tao->ops->setfromoptions = TaoSetFromOptions_NM; 253a7e14dcfSSatish Balay tao->ops->destroy = TaoDestroy_NM; 254a7e14dcfSSatish Balay 2556552cf8aSJason Sarich /* Override default settings (unless already changed) */ 256606f75f6SBarry Smith PetscCall(TaoParametersInitialize(tao)); 257606f75f6SBarry Smith PetscObjectParameterSetDefault(tao, max_it, 2000); 258606f75f6SBarry Smith PetscObjectParameterSetDefault(tao, max_funcs, 4000); 259a7e14dcfSSatish Balay 26083c8fe1dSLisandro Dalcin nm->simplex = NULL; 261a8d3b578SPierre Jolivet nm->lambda = 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; 2673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 268a7e14dcfSSatish Balay } 269