chiark / gitweb /
added test program and some test objectives
[nlopt.git] / api / nlopt.c
1 #include <stdlib.h>
2 #include <math.h>
3
4 #include "nlopt.h"
5 #include "config.h"
6
7 static const char nlopt_algorithm_names[NLOPT_NUM_ALGORITHMS][128] = {
8      "DIRECT (global)",
9      "Subplex (local)",
10      "StoGO (global)",
11      "Low-storage BFGS (LBFGS) (local)"
12 };
13
14 const char *nlopt_algorithm_name(nlopt_algorithm a)
15 {
16      if (a < 0 || a >= NLOPT_NUM_ALGORITHMS) return "UNKNOWN";
17      return nlopt_algorithm_names[a];
18 }
19
20 static int my_isinf(double x) {
21      return x == HUGE_VAL
22 #ifdef HAVE_ISINF
23           || isinf(x)
24 #endif
25           ;
26 }
27
28 #ifndef HAVE_ISNAN
29 static int my_isnan(double x) { return x != x; }
30 #  define isnan my_isnan
31 #endif
32
33 typedef struct {
34      nlopt_func f;
35      void *f_data;
36 } nlopt_data;
37
38 #include "subplex.h"
39
40 static double f_subplex(int n, const double *x, void *data_)
41 {
42      nlopt_data *data = (nlopt_data *) data_;
43      return data->f(n, x, NULL, data->f_data);
44 }
45
46 #include "direct.h"
47
48 static double f_direct(int n, const double *x, int *undefined, void *data_)
49 {
50      nlopt_data *data = (nlopt_data *) data_;
51      double f = data->f(n, x, NULL, data->f_data);
52      *undefined = isnan(f) || my_isinf(f);
53      return f;
54 }
55
56 #include "stogo.h"
57 #include "l-bfgs-b.h"
58
59 #define MIN(a,b) ((a) < (b) ? (a) : (b))
60
61 nlopt_result nlopt_minimize(
62      nlopt_algorithm algorithm,
63      int n, nlopt_func f, void *f_data,
64      const double *lb, const double *ub, /* bounds */
65      double *x, /* in: initial guess, out: minimizer */
66      double *fmin, /* out: minimum */
67      double fmin_max, double ftol_rel, double ftol_abs,
68      double xtol_rel, const double *xtol_abs,
69      int maxeval, double maxtime)
70 {
71      nlopt_data d;
72      d.f = f;
73      d.f_data = f_data;
74
75      switch (algorithm) {
76          case NLOPT_GLOBAL_DIRECT:
77               switch (direct_optimize(f_direct, &d, n, lb, ub, x, fmin,
78                                       maxeval, 500, ftol_rel, ftol_abs,
79                                       xtol_rel, xtol_rel,
80                                       DIRECT_UNKNOWN_FGLOBAL, -1.0,
81                                       NULL, DIRECT_GABLONSKY)) {
82                   case DIRECT_INVALID_BOUNDS:
83                   case DIRECT_MAXFEVAL_TOOBIG:
84                   case DIRECT_INVALID_ARGS:
85                        return NLOPT_INVALID_ARGS;
86                   case DIRECT_INIT_FAILED:
87                   case DIRECT_SAMPLEPOINTS_FAILED:
88                   case DIRECT_SAMPLE_FAILED:
89                        return NLOPT_FAILURE;
90                   case DIRECT_MAXFEVAL_EXCEEDED:
91                   case DIRECT_MAXITER_EXCEEDED:
92                        return NLOPT_MAXEVAL_REACHED;
93                   case DIRECT_GLOBAL_FOUND:
94                        return NLOPT_SUCCESS;
95                   case DIRECT_VOLTOL:
96                   case DIRECT_SIGMATOL:
97                        return NLOPT_XTOL_REACHED;
98                   case DIRECT_OUT_OF_MEMORY:
99                        return NLOPT_OUT_OF_MEMORY;
100               }
101               break;
102
103          case NLOPT_GLOBAL_STOGO:
104               if (!stogo_minimize(n, f, f_data, x, fmin, lb, ub,
105                                   maxeval, maxtime))
106                    return NLOPT_FAILURE;
107               break;
108
109          case NLOPT_LOCAL_SUBPLEX: {
110               int iret, i;
111               double *scale = (double *) malloc(sizeof(double) * n);
112               if (!scale) return NLOPT_OUT_OF_MEMORY;
113               for (i = 0; i < n; ++i)
114                    scale[i] = fabs(ub[i] - lb[i]);
115               iret = subplex(f_subplex, fmin, x, n, &d, xtol_rel, maxeval,
116                              fmin_max, !my_isinf(fmin_max), scale);
117               free(scale);
118               switch (iret) {
119                   case -2: return NLOPT_INVALID_ARGS;
120                   case -1: return NLOPT_MAXEVAL_REACHED;
121                   case 0: return NLOPT_XTOL_REACHED;
122                   case 1: return NLOPT_SUCCESS;
123                   case 2: return NLOPT_FMIN_MAX_REACHED;
124               }
125               break;
126          }
127
128          case NLOPT_LOCAL_LBFGS: {
129               int iret, i, *nbd = (int *) malloc(sizeof(int) * n);
130               if (!nbd) return NLOPT_OUT_OF_MEMORY;
131               for (i = 0; i < n; ++i) {
132                    int linf = my_isinf(lb[i]) && lb[i] < 0;
133                    int uinf = my_isinf(ub[i]) && ub[i] > 0;
134                    nbd[i] = linf && uinf ? 0 : (uinf ? 1 : (linf ? 3 : 2));
135               }
136               iret = lbfgsb_minimize(n, f, f_data, x, nbd, lb, ub,
137                                      MIN(n, 5), 0.0, ftol_rel, 
138                                      xtol_abs ? xtol_rel : *xtol_abs,
139                                      maxeval);
140               free(nbd);
141               if (iret <= 0) {
142                    switch (iret) {
143                        case -1: return NLOPT_INVALID_ARGS;
144                        case -2: default: return NLOPT_FAILURE;
145                    }
146               }
147               else {
148                    *fmin = f(n, x, NULL, f_data);
149                    switch (iret) {
150                        case 5: return NLOPT_MAXEVAL_REACHED;
151                        case 2: return NLOPT_XTOL_REACHED;
152                        case 1: return NLOPT_FTOL_REACHED;
153                        default: return NLOPT_SUCCESS;
154                    }
155               }
156               break;
157          }
158
159          default:
160               return NLOPT_INVALID_ARGS;
161      }
162
163      return NLOPT_SUCCESS;
164 }