Beispiel #1
0
/* 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];
     }
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
/* 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;
}
Beispiel #6
0
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;
}