nlopt.c 5.1 KB
Newer Older
S
stevenj 已提交
1 2 3 4
#include <stdlib.h>
#include <math.h>

#include "nlopt.h"
S
stevenj 已提交
5 6
#include "config.h"

7 8
static const char nlopt_algorithm_names[NLOPT_NUM_ALGORITHMS][128] = {
     "DIRECT (global)",
9
     "DIRECT-L (global)",
10 11 12 13 14 15 16 17 18 19 20
     "Subplex (local)",
     "StoGO (global)",
     "Low-storage BFGS (LBFGS) (local)"
};

const char *nlopt_algorithm_name(nlopt_algorithm a)
{
     if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
     return nlopt_algorithm_names[a];
}

S
stevenj 已提交
21 22 23 24 25 26 27 28 29 30 31 32
static int my_isinf(double x) {
     return x == HUGE_VAL
#ifdef HAVE_ISINF
	  || isinf(x)
#endif
	  ;
}

#ifndef HAVE_ISNAN
static int my_isnan(double x) { return x != x; }
#  define isnan my_isnan
#endif
S
stevenj 已提交
33 34 35 36

typedef struct {
     nlopt_func f;
     void *f_data;
37
     const double *lb, *ub;
S
stevenj 已提交
38 39 40 41
} nlopt_data;

#include "subplex.h"

S
stevenj 已提交
42
static double f_subplex(int n, const double *x, void *data_)
S
stevenj 已提交
43
{
44
     int i;
S
stevenj 已提交
45
     nlopt_data *data = (nlopt_data *) data_;
46 47 48 49 50 51 52 53 54 55 56

     /* subplex does not support bound constraints, but it supports
	discontinuous objectives so we can just return Inf for invalid x */
     for (i = 0; i < n; ++i)
	  if (x[i] < data->lb[i] || x[i] > data->ub[i])
#ifdef INFINITY
	       return INFINITY;
#else
	       return HUGE_VAL;
#endif

S
stevenj 已提交
57
     return data->f(n, x, NULL, data->f_data);
S
stevenj 已提交
58 59 60 61
}

#include "direct.h"

S
stevenj 已提交
62
static double f_direct(int n, const double *x, int *undefined, void *data_)
S
stevenj 已提交
63 64
{
     nlopt_data *data = (nlopt_data *) data_;
S
stevenj 已提交
65 66
     double f = data->f(n, x, NULL, data->f_data);
     *undefined = isnan(f) || my_isinf(f);
S
stevenj 已提交
67 68 69
     return f;
}

S
stevenj 已提交
70 71 72 73
#include "stogo.h"
#include "l-bfgs-b.h"

#define MIN(a,b) ((a) < (b) ? (a) : (b))
S
stevenj 已提交
74 75

nlopt_result nlopt_minimize(
76
     nlopt_algorithm algorithm,
S
stevenj 已提交
77 78 79 80
     int n, nlopt_func f, void *f_data,
     const double *lb, const double *ub, /* bounds */
     double *x, /* in: initial guess, out: minimizer */
     double *fmin, /* out: minimum */
S
stevenj 已提交
81
     double fmin_max, double ftol_rel, double ftol_abs,
S
stevenj 已提交
82 83 84
     double xtol_rel, const double *xtol_abs,
     int maxeval, double maxtime)
{
85
     int i;
S
stevenj 已提交
86 87 88
     nlopt_data d;
     d.f = f;
     d.f_data = f_data;
89 90 91 92 93 94 95
     d.lb = lb;
     d.ub = ub;

     /* check bound constraints */
     for (i = 0; i < n; ++i)
	  if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i])
	       return NLOPT_INVALID_ARGS;
S
stevenj 已提交
96

97
     switch (algorithm) {
S
stevenj 已提交
98
	 case NLOPT_GLOBAL_DIRECT:
99
	 case NLOPT_GLOBAL_DIRECT_L:
S
stevenj 已提交
100 101 102 103
	      switch (direct_optimize(f_direct, &d, n, lb, ub, x, fmin,
				      maxeval, 500, ftol_rel, ftol_abs,
				      xtol_rel, xtol_rel,
				      DIRECT_UNKNOWN_FGLOBAL, -1.0,
104 105 106 107
				      NULL, 
				      algorithm == NLOPT_GLOBAL_DIRECT
				      ? DIRECT_ORIGINAL
				      : DIRECT_GABLONSKY)) {
S
stevenj 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
		  case DIRECT_INVALID_BOUNDS:
		  case DIRECT_MAXFEVAL_TOOBIG:
		  case DIRECT_INVALID_ARGS:
		       return NLOPT_INVALID_ARGS;
		  case DIRECT_INIT_FAILED:
		  case DIRECT_SAMPLEPOINTS_FAILED:
		  case DIRECT_SAMPLE_FAILED:
		       return NLOPT_FAILURE;
		  case DIRECT_MAXFEVAL_EXCEEDED:
		  case DIRECT_MAXITER_EXCEEDED:
		       return NLOPT_MAXEVAL_REACHED;
		  case DIRECT_GLOBAL_FOUND:
		       return NLOPT_SUCCESS;
		  case DIRECT_VOLTOL:
		  case DIRECT_SIGMATOL:
		       return NLOPT_XTOL_REACHED;
		  case DIRECT_OUT_OF_MEMORY:
		       return NLOPT_OUT_OF_MEMORY;
S
stevenj 已提交
126 127 128 129 130 131 132 133 134 135
	      }
	      break;

	 case NLOPT_GLOBAL_STOGO:
	      if (!stogo_minimize(n, f, f_data, x, fmin, lb, ub,
				  maxeval, maxtime))
		   return NLOPT_FAILURE;
	      break;

	 case NLOPT_LOCAL_SUBPLEX: {
136
	      int iret;
S
stevenj 已提交
137 138
	      double *scale = (double *) malloc(sizeof(double) * n);
	      if (!scale) return NLOPT_OUT_OF_MEMORY;
139 140 141 142 143 144 145 146 147 148
	      for (i = 0; i < n; ++i) {
		   if (!my_isinf(ub[i]) && !my_isinf(lb[i]))
			scale[i] = (ub[i] - lb[i]) * 0.01;
		   else if (!my_isinf(lb[i]) && x[i] > lb[i])
			scale[i] = (x[i] - lb[i]) * 0.01;
		   else if (!my_isinf(ub[i]) && x[i] < ub[i])
			scale[i] = (ub[i] - x[i]) * 0.01;
		   else
			scale[i] = 0.01 * x[i] + 0.0001;
	      }
S
stevenj 已提交
149
	      iret = subplex(f_subplex, fmin, x, n, &d, xtol_rel, maxeval,
S
stevenj 已提交
150
			     fmin_max, !my_isinf(fmin_max), scale);
S
stevenj 已提交
151 152
	      free(scale);
	      switch (iret) {
S
stevenj 已提交
153 154 155 156 157
		  case -2: return NLOPT_INVALID_ARGS;
		  case -1: return NLOPT_MAXEVAL_REACHED;
		  case 0: return NLOPT_XTOL_REACHED;
		  case 1: return NLOPT_SUCCESS;
		  case 2: return NLOPT_FMIN_MAX_REACHED;
S
stevenj 已提交
158 159 160 161 162
	      }
	      break;
	 }

	 case NLOPT_LOCAL_LBFGS: {
163
	      int iret, *nbd = (int *) malloc(sizeof(int) * n);
S
stevenj 已提交
164 165
	      if (!nbd) return NLOPT_OUT_OF_MEMORY;
	      for (i = 0; i < n; ++i) {
S
stevenj 已提交
166 167
		   int linf = my_isinf(lb[i]) && lb[i] < 0;
		   int uinf = my_isinf(ub[i]) && ub[i] > 0;
S
stevenj 已提交
168 169 170 171
		   nbd[i] = linf && uinf ? 0 : (uinf ? 1 : (linf ? 3 : 2));
	      }
	      iret = lbfgsb_minimize(n, f, f_data, x, nbd, lb, ub,
				     MIN(n, 5), 0.0, ftol_rel, 
S
whoops  
stevenj 已提交
172
				     xtol_abs ? *xtol_abs : xtol_rel,
S
stevenj 已提交
173 174 175 176
				     maxeval);
	      free(nbd);
	      if (iret <= 0) {
		   switch (iret) {
S
stevenj 已提交
177 178
		       case -1: return NLOPT_INVALID_ARGS;
		       case -2: default: return NLOPT_FAILURE;
S
stevenj 已提交
179 180 181 182 183
		   }
	      }
	      else {
		   *fmin = f(n, x, NULL, f_data);
		   switch (iret) {
S
stevenj 已提交
184 185 186
		       case 5: return NLOPT_MAXEVAL_REACHED;
		       case 2: return NLOPT_XTOL_REACHED;
		       case 1: return NLOPT_FTOL_REACHED;
S
stevenj 已提交
187 188 189 190 191 192 193 194 195 196 197 198
		       default: return NLOPT_SUCCESS;
		   }
	      }
	      break;
	 }

	 default:
	      return NLOPT_INVALID_ARGS;
     }

     return NLOPT_SUCCESS;
}