/* set x to a random trial value, as defined by CRS: x = 2G - x_n, where x_0 ... x_n are distinct points in the population with x_0 the current best point and the other points are random, and G is the centroid of x_0...x_{n-1} */ static void random_trial(crs_data *d, double *x, rb_node *best) { int n = d->n, n1 = n+1, i, k, i0, jn; double *ps = d->ps, *xi; /* initialize x to x_0 = best point */ memcpy(x, best->k + 1, sizeof(double) * n); i0 = (best->k - ps) / n1; jn = nlopt_iurand(n); /* which of remaining n points is "x_n", i.e. which to reflect through ... this is necessary since we generate the remaining points in order, so just picking the last point would not be very random */ /* use "method A" from Jeffrey Scott Vitter, "An efficient algorithm for sequential random sampling," ACM Trans. Math. Soft. 13 (1), 58--67 (1987). to randomly pick n distinct points out of the remaining N-1 (not including i0!). (The same as "method S" in Knuth vol. 2.) This method requires O(N) time, which is fine in our case (there are better methods if n << N). */ { int Nleft = d->N - 1, nleft = n; int Nfree = Nleft - nleft; i = 0; i += i == i0; while (nleft > 1) { double q = ((double) Nfree) / Nleft; double v = nlopt_urand(0., 1.); while (q > v) { ++i; i += i == i0; --Nfree; --Nleft; q = (q * Nfree) / Nleft; } xi = ps + n1 * i + 1; if (jn-- == 0) /* point to reflect through */ for (k = 0; k < n; ++k) x[k] -= xi[k] * (0.5*n); else /* point to include in centroid */ for (k = 0; k < n; ++k) x[k] += xi[k]; ++i; i += i == i0; --Nleft; --nleft; } i += nlopt_iurand(Nleft); i += i == i0; xi = ps + n1 * i + 1; if (jn-- == 0) /* point to reflect through */ for (k = 0; k < n; ++k) x[k] -= xi[k] * (0.5*n); else /* point to include in centroid */ for (k = 0; k < n; ++k) x[k] += xi[k]; } for (k = 0; k < n; ++k) { x[k] *= 2.0 / n; /* renormalize */ if (x[k] > d->ub[k]) x[k] = d->ub[k]; else if (x[k] < d->lb[k]) x[k] = d->lb[k]; } }
nlopt_result chevolutionarystrategy( unsigned nparameters, /* Number of input parameters */ nlopt_func f, /* Recursive Objective Funtion Call */ void * data_f, /* Data to Objective Function */ const double* lb, /* Lower bound values */ const double* ub, /* Upper bound values */ double* x, /*in: initial guess, out: minimizer */ double* minf, nlopt_stopping* stop, /* nlopt stop condition */ unsigned np, /* Number of Parents */ unsigned no) { /* Number of Offsprings */ /* variables from nlopt */ nlopt_result ret = NLOPT_SUCCESS; double vetor[8]; unsigned i, id, item; int parent1, parent2; unsigned crosspoint; /* crossover parameteres */ int contmutation, totalmutation; /* mutation parameters */ int idoffmutation, paramoffmutation; /* mutation parameters */ Individual * esparents; /* Parents population */ Individual * esoffsprings; /* Offsprings population */ Individual * estotal;/* copy containing Parents and Offsprings pops */ /* It is interesting to maintain the parents and offsprings * populations stablished and sorted; when the final iterations * is achieved, they are ranked and updated. */ /********************************* * controling the population size *********************************/ if (!np) np = 40; if (!no) no = 60; if ((np < 1)||(no<1)) { nlopt_stop_msg(stop, "populations %d, %d are too small", np, no); return NLOPT_INVALID_ARGS; } esparents = (Individual*) malloc(sizeof(Individual) * np); esoffsprings = (Individual*) malloc(sizeof(Individual) * no); estotal = (Individual*) malloc(sizeof(Individual) * (np+no)); if ((!esparents)||(!esoffsprings)||(!estotal)) { free(esparents); free(esoffsprings); free(estotal); return NLOPT_OUT_OF_MEMORY; } for (id=0; id < np; id++) esparents[id].parameters = NULL; for (id=0; id < no; id++) esoffsprings[id].parameters = NULL; /* From here the population is initialized */ /* we don't handle unbounded search regions; this check is unnecessary since it is performed in nlopt_optimize. for (j = 0; j < nparameters; ++j) if (nlopt_isinf(low[j]) || nlopt_isinf(up[j])) return NLOPT_INVALID_ARGS; */ /* main vector of parameters to randcauchy */ vetor[0] = 4; /* ignored */ vetor[3] = 0; vetor[4] = 1; vetor[5] = 10; vetor[6] = 1; vetor[7] = 0; /* ignored */ /************************************** * Initializing parents population **************************************/ for (id=0; id < np; id++) { esparents[id].parameters = (double*) malloc(sizeof(double) * nparameters); if (!esparents[id].parameters) { ret = NLOPT_OUT_OF_MEMORY; goto done; } for (item=0; item<nparameters; item++) { vetor[1] = lb[item]; vetor[2] = ub[item]; vetor[7]=vetor[7]+1; esparents[id].parameters[item] = randcauchy(vetor); } } memcpy(esparents[0].parameters, x, nparameters * sizeof(double)); /************************************** * Initializing offsprings population **************************************/ for (id=0; id < no; id++) { esoffsprings[id].parameters = (double*) malloc(sizeof(double) * nparameters); if (!esoffsprings[id].parameters) { ret = NLOPT_OUT_OF_MEMORY; goto done; } for (item=0; item<nparameters; item++) { vetor[1] = lb[item]; vetor[2] = ub[item]; vetor[7]=vetor[7]+1; esoffsprings[id].parameters[item] = randcauchy(vetor); } } /************************************** * Parents fitness evaluation **************************************/ for (id=0; id < np; id++) { esparents[id].fitness = f(nparameters, esparents[id].parameters, NULL, data_f); estotal[id].fitness = esparents[id].fitness; stop->nevals++; if (*minf > esparents[id].fitness) { *minf = esparents[id].fitness; memcpy(x, esparents[id].parameters, nparameters * sizeof(double)); } if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP; else if (*minf < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED; else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED; else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED; if (ret != NLOPT_SUCCESS) goto done; } /************************************** * Main Loop - Generations **************************************/ while (1) { /************************************** * Crossover **************************************/ for (id=0; id < no; id++) { parent1 = nlopt_iurand((int) np); parent2 = nlopt_iurand((int) np); crosspoint = (unsigned) nlopt_iurand((int) nparameters); for (item=0; item < crosspoint; item++) esoffsprings[id].parameters[item] = esparents[parent1].parameters[item]; for (item=crosspoint; item < nparameters; item++) esoffsprings[id].parameters[item] = esparents[parent2].parameters[item]; } /************************************** * Gaussian Mutation **************************************/ totalmutation = (int) ((no * nparameters) / 10); if (totalmutation < 1) totalmutation = 1; for (contmutation=0; contmutation < totalmutation; contmutation++) { idoffmutation = nlopt_iurand((int) no); paramoffmutation = nlopt_iurand((int) nparameters); vetor[1] = lb[paramoffmutation]; vetor[2] = ub[paramoffmutation]; vetor[7] = vetor[7]+contmutation; esoffsprings[idoffmutation].parameters[paramoffmutation] = randcauchy(vetor); } /************************************** * Offsprings fitness evaluation **************************************/ for (id=0; id < no; id++){ /*esoffsprings[id].fitness = (double)fitness(esoffsprings[id].parameters, nparameters,fittype);*/ esoffsprings[id].fitness = f(nparameters, esoffsprings[id].parameters, NULL, data_f); estotal[id+np].fitness = esoffsprings[id].fitness; stop->nevals++; if (*minf > esoffsprings[id].fitness) { *minf = esoffsprings[id].fitness; memcpy(x, esoffsprings[id].parameters, nparameters * sizeof(double)); } if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP; else if (*minf < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED; else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED; else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED; if (ret != NLOPT_SUCCESS) goto done; } /************************************** * Individual selection **************************************/ /* all the individuals are copied to one vector to easily identify best solutions */ for (i=0; i < np; i++) estotal[i] = esparents[i]; for (i=0; i < no; i++) estotal[np+i] = esoffsprings[i]; /* Sorting */ nlopt_qsort_r(estotal, no+np, sizeof(Individual), NULL, CompareIndividuals); /* copy after sorting: */ for (i=0; i < no+np; i++) { if (i<np) esparents[i] = estotal[i]; else esoffsprings[i-np] = estotal[i]; } } /* generations loop */ done: for (id=0; id < np; id++) free(esparents[id].parameters); for (id=0; id < no; id++) free(esoffsprings[id].parameters); if (esparents) free(esparents); if (esoffsprings) free(esoffsprings); if (estotal) free(estotal); return ret; }
static nlopt_result divide_largest(params *p) { int L = p->L; int n = p->n; rb_node *node = rb_tree_max(&p->rtree); /* just using it as a heap */ double minf_start = p->minf; double *r = node->k, *rnew = NULL; double *x = r + 3, *c = x + n, *w = c + n; const double *lb = p->lb, *ub = p->ub; int i, idiv; double wmax; nlopt_result ret; /* printf("rect:, %d, %g, %g, %g, %g\n", p->stop->nevals, c[0], c[1], w[0], w[1]); */ /* check xtol */ for (i = 0; i < n; ++i) if (w[i] > p->stop->xtol_rel * (ub[i] - lb[i]) && w[i] > p->stop->xtol_abs[i]) break; if (i == n) return NLOPT_XTOL_REACHED; if (p->randomized_div) { /* randomly pick among ~largest sides */ int nlongest = 0; wmax = longest(n, w); for (i = 0; i < n; ++i) if (wmax - w[i] < EQUAL_SIDE_TOL * wmax) ++nlongest; i = 1 + nlopt_iurand(nlongest); for (idiv = 0; idiv < n; ++idiv) { if (wmax - w[idiv] < EQUAL_SIDE_TOL * wmax) --i; if (!i) break; } } else { /* just pick first largest side */ wmax = w[idiv = 0]; for (i = 1; i < n; ++i) if (w[i] > wmax) wmax = w[idiv = i]; } if (fabs(x[idiv] - c[idiv]) > (0.5 * THIRD) * w[idiv]) { /* bisect */ double deltac = (x[idiv] > c[idiv] ? 0.25 : -0.25) * w[idiv]; w[idiv] *= 0.5; c[idiv] += deltac; r[0] = longest(n, w); /* new diameter */ /* r[1] unchanged since still contains local optimum x */ r[2] = p->age--; node = rb_tree_resort(&p->rtree, node); rnew = (double *) malloc(sizeof(double) * L); if (!rnew) return NLOPT_OUT_OF_MEMORY; memcpy(rnew, r, sizeof(double) * L); rnew[2] = p->age--; rnew[3+n+idiv] -= deltac*2; if (p->randomized_div) randomize_x(n, rnew); else memcpy(rnew+3, rnew+3+n, sizeof(double) * n); /* x = c */ ret = optimize_rect(rnew, p); if (ret != NLOPT_SUCCESS) { free(rnew); return ret; } if (!rb_tree_insert(&p->rtree, rnew)) { free(rnew); return NLOPT_OUT_OF_MEMORY; } } else { /* trisect */ w[idiv] *= THIRD; r[0] = longest(n, w); /* r[1] unchanged since still contains local optimum x */ r[2] = p->age--; node = rb_tree_resort(&p->rtree, node); for (i = -1; i <= +1; i += 2) { rnew = (double *) malloc(sizeof(double) * L); if (!rnew) return NLOPT_OUT_OF_MEMORY; memcpy(rnew, r, sizeof(double) * L); rnew[2] = p->age--; rnew[3+n+idiv] += w[i] * i; if (p->randomized_div) randomize_x(n, rnew); else memcpy(rnew+3, rnew+3+n, sizeof(double) * n); /* x = c */ ret = optimize_rect(rnew, p); if (ret != NLOPT_SUCCESS) { free(rnew); return ret; } if (!rb_tree_insert(&p->rtree, rnew)) { free(rnew); return NLOPT_OUT_OF_MEMORY; } } } if (p->minf < minf_start && nlopt_stop_f(p->stop, p->minf, minf_start)) return NLOPT_FTOL_REACHED; return NLOPT_SUCCESS; }
static nlopt_result divide_good_rects(params *p) { const int n = p->n; double **hull; int nhull, i, xtol_reached = 1, divided_some = 0; double magic_eps = p->magic_eps; if (p->hull_len < p->rtree.N) { p->hull_len += p->rtree.N; p->hull = (double **) realloc(p->hull, sizeof(double*)*p->hull_len); if (!p->hull) return NLOPT_OUT_OF_MEMORY; } nhull = convex_hull(&p->rtree, hull = p->hull, p->which_opt != 1); divisions: for (i = 0; i < nhull; ++i) { double K1 = -HUGE_VAL, K2 = -HUGE_VAL, K; int im, ip; /* find unequal points before (im) and after (ip) to get slope */ for (im = i-1; im >= 0 && hull[im][0] == hull[i][0]; --im) ; for (ip = i+1; ip < nhull && hull[ip][0] == hull[i][0]; ++ip) ; if (im >= 0) K1 = (hull[i][1] - hull[im][1]) / (hull[i][0] - hull[im][0]); if (ip < nhull) K2 = (hull[i][1] - hull[ip][1]) / (hull[i][0] - hull[ip][0]); K = MAX(K1, K2); if (hull[i][1] - K * hull[i][0] <= p->minf - magic_eps * fabs(p->minf) || ip == nhull) { /* "potentially optimal" rectangle, so subdivide */ nlopt_result ret = divide_rect(hull[i], p); divided_some = 1; if (ret != NLOPT_SUCCESS) return ret; xtol_reached = xtol_reached && small(hull[i] + 3+n, p); } /* for the DIRECT-L variant, we only divide one rectangle out of all points with equal diameter and function values ... note that for p->which_opt == 1, i == ip-1 should be a no-op anyway, since we set allow_dups=0 in convex_hull above */ if (p->which_opt == 1) i = ip - 1; /* skip to next unequal point for next iteration */ else if (p->which_opt == 2) /* like DIRECT-L but randomized */ i += nlopt_iurand(ip - i); /* possibly do another equal pt */ } if (!divided_some) { if (magic_eps != 0) { magic_eps = 0; goto divisions; /* try again */ } else { /* WTF? divide largest rectangle with smallest f */ /* (note that this code actually gets called from time to time, and the heuristic here seems to work well, but I don't recall this situation being discussed in the references?) */ rb_node *max = rb_tree_max(&p->rtree); rb_node *pred = max; double wmax = max->k[0]; do { /* note: this loop is O(N) worst-case time */ max = pred; pred = rb_tree_pred(max); } while (pred && pred->k[0] == wmax); return divide_rect(max->k, p); } } return xtol_reached ? NLOPT_XTOL_REACHED : NLOPT_SUCCESS; }
/* divide rectangle idiv in the list p->rects */ static nlopt_result divide_rect(double *rdiv, params *p) { int i; const int n = p->n; const int L = p->L; double *c = rdiv + 3; /* center of rect to divide */ double *w = c + n; /* widths of rect to divide */ double wmax = w[0]; int imax = 0, nlongest = 0; rb_node *node; for (i = 1; i < n; ++i) if (w[i] > wmax) wmax = w[imax = i]; for (i = 0; i < n; ++i) if (wmax - w[i] <= wmax * EQUAL_SIDE_TOL) ++nlongest; if (p->which_div == 1 || (p->which_div == 0 && nlongest == n)) { /* trisect all longest sides, in increasing order of the average function value along that direction */ double *fv = p->work; int *isort = p->iwork; for (i = 0; i < n; ++i) { if (wmax - w[i] <= wmax * EQUAL_SIDE_TOL) { double csave = c[i]; c[i] = csave - w[i] * THIRD; FUNCTION_EVAL(fv[2*i], c, p, 0); c[i] = csave + w[i] * THIRD; FUNCTION_EVAL(fv[2*i+1], c, p, 0); c[i] = csave; } else { fv[2*i] = fv[2*i+1] = HUGE_VAL; } } sort_fv(n, fv, isort); if (!(node = rb_tree_find(&p->rtree, rdiv))) return NLOPT_FAILURE; for (i = 0; i < nlongest; ++i) { int k; w[isort[i]] *= THIRD; rdiv[0] = rect_diameter(n, w, p); rdiv[2] = p->age++; node = rb_tree_resort(&p->rtree, node); for (k = 0; k <= 1; ++k) { double *rnew; ALLOC_RECT(rnew, L); memcpy(rnew, rdiv, sizeof(double) * L); rnew[3 + isort[i]] += w[isort[i]] * (2*k-1); rnew[1] = fv[2*isort[i]+k]; rnew[2] = p->age++; if (!rb_tree_insert(&p->rtree, rnew)) { free(rnew); return NLOPT_OUT_OF_MEMORY; } } } } else { int k; if (nlongest > 1 && p->which_div == 2) { /* randomly choose longest side */ i = nlopt_iurand(nlongest); for (k = 0; k < n; ++k) if (wmax - w[k] <= wmax * EQUAL_SIDE_TOL) { if (!i) { i = k; break; } --i; } } else i = imax; /* trisect longest side */ if (!(node = rb_tree_find(&p->rtree, rdiv))) return NLOPT_FAILURE; w[i] *= THIRD; rdiv[0] = rect_diameter(n, w, p); rdiv[2] = p->age++; node = rb_tree_resort(&p->rtree, node); for (k = 0; k <= 1; ++k) { double *rnew; ALLOC_RECT(rnew, L); memcpy(rnew, rdiv, sizeof(double) * L); rnew[3 + i] += w[i] * (2*k-1); FUNCTION_EVAL(rnew[1], rnew + 3, p, rnew); rnew[2] = p->age++; if (!rb_tree_insert(&p->rtree, rnew)) { free(rnew); return NLOPT_OUT_OF_MEMORY; } } } return NLOPT_SUCCESS; }
static int test_function(int ifunc) { testfunc func; int i, iter; double *x, minf, minf_max, f0, *xtabs, *lb, *ub; nlopt_result ret; double start = nlopt_seconds(); int total_count = 0, max_count = 0, min_count = 1<<30; double total_err = 0, max_err = 0; bounds_wrap_data bw; if (ifunc < 0 || ifunc >= NTESTFUNCS) { fprintf(stderr, "testopt: invalid function %d\n", ifunc); listfuncs(stderr); return 0; } func = testfuncs[ifunc]; x = (double *) malloc(sizeof(double) * func.n * 5); if (!x) { fprintf(stderr, "testopt: Out of memory!\n"); return 0; } lb = x + func.n * 3; ub = lb + func.n; xtabs = x + func.n * 2; bw.lb = lb; bw.ub = ub; bw.f = func.f; bw.f_data = func.f_data; for (i = 0; i < func.n; ++i) xtabs[i] = xtol_abs; minf_max = minf_max_delta > (-HUGE_VAL) ? minf_max_delta + func.minf : (-HUGE_VAL); printf("-----------------------------------------------------------\n"); printf("Optimizing %s (%d dims) using %s algorithm\n", func.name, func.n, nlopt_algorithm_name(algorithm)); printf("lower bounds at lb = ["); for (i = 0; i < func.n; ++i) printf(" %g", func.lb[i]); printf("]\n"); printf("upper bounds at ub = ["); for (i = 0; i < func.n; ++i) printf(" %g", func.ub[i]); printf("]\n"); memcpy(lb, func.lb, func.n * sizeof(double)); memcpy(ub, func.ub, func.n * sizeof(double)); for (i = 0; i < func.n; ++i) if (fix_bounds[i]) { printf("fixing bounds for dim[%d] to xmin[%d]=%g\n", i, i, func.xmin[i]); lb[i] = ub[i] = func.xmin[i]; } if (force_constraints) { for (i = 0; i < func.n; ++i) { if (nlopt_iurand(2) == 0) ub[i] = nlopt_urand(lb[i], func.xmin[i]); else lb[i] = nlopt_urand(func.xmin[i], ub[i]); } printf("adjusted lower bounds at lb = ["); for (i = 0; i < func.n; ++i) printf(" %g", lb[i]); printf("]\n"); printf("adjusted upper bounds at ub = ["); for (i = 0; i < func.n; ++i) printf(" %g", ub[i]); printf("]\n"); } if (fabs(func.f(func.n, func.xmin, 0, func.f_data) - func.minf) > 1e-8) { fprintf(stderr, "BUG: function does not achieve given lower bound!\n"); fprintf(stderr, "f(%g", func.xmin[0]); for (i = 1; i < func.n; ++i) fprintf(stderr, ", %g", func.xmin[i]); fprintf(stderr, ") = %0.16g instead of %0.16g, |diff| = %g\n", func.f(func.n, func.xmin, 0, func.f_data), func.minf, fabs(func.f(func.n, func.xmin, 0, func.f_data) - func.minf)); return 0; } for (iter = 0; iter < iterations; ++iter) { double val; testfuncs_counter = 0; printf("Starting guess x = ["); for (i = 0; i < func.n; ++i) { if (center_start) x[i] = (ub[i] + lb[i]) * 0.5; else if (xinit_tol < 0) { /* random starting point near center of box */ double dx = (ub[i] - lb[i]) * 0.25; double xm = 0.5 * (ub[i] + lb[i]); x[i] = nlopt_urand(xm - dx, xm + dx); } else { x[i] = nlopt_urand(-xinit_tol, xinit_tol) + (1 + nlopt_urand(-xinit_tol, xinit_tol)) * func.xmin[i]; if (x[i] > ub[i]) x[i] = ub[i]; else if (x[i] < lb[i]) x[i] = lb[i]; } printf(" %g", x[i]); } printf("]\n"); f0 = func.f(func.n, x, x + func.n, func.f_data); printf("Starting function value = %g\n", f0); if (iter == 0 && testfuncs_verbose && func.has_gradient) { printf("checking gradient:\n"); for (i = 0; i < func.n; ++i) { double f; x[i] *= 1 + 1e-6; f = func.f(func.n, x, NULL, func.f_data); x[i] /= 1 + 1e-6; printf(" grad[%d] = %g vs. numerical derivative %g\n", i, x[i + func.n], (f - f0) / (x[i] * 1e-6)); } } testfuncs_counter = 0; ret = nlopt_minimize(algorithm, func.n, bounds_wrap_func, &bw, lb, ub, x, &minf, minf_max, ftol_rel, ftol_abs, xtol_rel, xtabs, maxeval, maxtime); printf("finished after %g seconds.\n", nlopt_seconds() - start); printf("return code %d from nlopt_minimize\n", ret); if (ret < 0 && ret != NLOPT_ROUNDOFF_LIMITED && ret != NLOPT_FORCED_STOP) { fprintf(stderr, "testopt: error in nlopt_minimize\n"); free(x); return 0; } printf("Found minimum f = %g after %d evaluations.\n", minf, testfuncs_counter); total_count += testfuncs_counter; if (testfuncs_counter > max_count) max_count = testfuncs_counter; if (testfuncs_counter < min_count) min_count = testfuncs_counter; printf("Minimum at x = ["); for (i = 0; i < func.n; ++i) printf(" %g", x[i]); printf("]\n"); if (func.minf == 0) printf("|f - minf| = %g\n", fabs(minf - func.minf)); else printf("|f - minf| = %g, |f - minf| / |minf| = %e\n", fabs(minf - func.minf), fabs(minf - func.minf) / fabs(func.minf)); total_err += fabs(minf - func.minf); if (fabs(minf - func.minf) > max_err) max_err = fabs(minf - func.minf); printf("vs. global minimum f = %g at x = [", func.minf); for (i = 0; i < func.n; ++i) printf(" %g", func.xmin[i]); printf("]\n"); val = func.f(func.n, x, NULL, func.f_data); if (val != minf) { fprintf(stderr, "Mismatch %g between returned minf=%g and f(x) = %g\n", minf - val, minf, val); free(x); return 0; } } if (iterations > 1) printf("average #evaluations = %g (%d-%d)\naverage |f-minf| = %g, max |f-minf| = %g\n", total_count * 1.0 / iterations, min_count, max_count, total_err / iterations, max_err); free(x); return 1; }