chiark / gitweb /
added ISRES (compiles, but untested)
authorstevenj <stevenj@alum.mit.edu>
Wed, 18 Nov 2009 05:52:59 +0000 (00:52 -0500)
committerstevenj <stevenj@alum.mit.edu>
Wed, 18 Nov 2009 05:52:59 +0000 (00:52 -0500)
darcs-hash:20091118055259-c8de0-1b704e09a6a759e72345cdd1833c9756e3880663.gz

Makefile.am
api/Makefile.am
api/nlopt.c
api/nlopt.h
configure.ac
isres/Makefile.am [new file with mode: 0644]
isres/README [new file with mode: 0644]
isres/isres.c [new file with mode: 0644]
isres/isres.h [new file with mode: 0644]
util/mt19937ar.c
util/nlopt-util.h

index f1d1e6f70221f08bc79dadd61a09f47c09814608..6e67693c2bf9f7505cb6b7cb885428b2a4c93ac1 100644 (file)
@@ -8,7 +8,7 @@ CXX_DIRS = stogo
 CXX_LIBS = stogo/libstogo.la
 endif
 
-SUBDIRS = util direct cdirect $(CXX_DIRS) praxis luksan crs mlsl mma cobyla newuoa lbfgs neldermead auglag bobyqa api . octave test
+SUBDIRS = util direct cdirect $(CXX_DIRS) praxis luksan crs mlsl mma cobyla newuoa lbfgs neldermead auglag bobyqa isres api . octave test
 EXTRA_DIST = autogen.sh nlopt.pc.in m4
 
 if WITH_NOCEDAL
@@ -16,10 +16,12 @@ NOCEDAL_LBFGS=lbfgs/liblbfgs.la
 endif
 
 libnlopt@NLOPT_SUFFIX@_la_SOURCES = 
-libnlopt@NLOPT_SUFFIX@_la_LIBADD = \
-direct/libdirect.la cdirect/libcdirect.la $(CXX_LIBS)                  \
-praxis/libpraxis.la $(NOCEDAL_LBFGS) luksan/libluksan.la crs/libcrs.la \
-mlsl/libmlsl.la mma/libmma.la cobyla/libcobyla.la newuoa/libnewuoa.la neldermead/libneldermead.la auglag/libauglag.la bobyqa/libbobyqa.la api/libapi.la util/libutil.la
+libnlopt@NLOPT_SUFFIX@_la_LIBADD = direct/libdirect.la                 \
+cdirect/libcdirect.la $(CXX_LIBS) praxis/libpraxis.la $(NOCEDAL_LBFGS) \
+luksan/libluksan.la crs/libcrs.la mlsl/libmlsl.la mma/libmma.la                \
+cobyla/libcobyla.la newuoa/libnewuoa.la neldermead/libneldermead.la    \
+auglag/libauglag.la bobyqa/libbobyqa.la isres/libisres.la              \
+api/libapi.la util/libutil.la
 
 libnlopt@NLOPT_SUFFIX@_la_LDFLAGS = -no-undefined -version-info @SHARED_VERSION_INFO@
 
index 0683def16ba7fcd2f0afc19b970dea6e38fc2372..3e2f5ce40a8ceedeff9094e71ecd41605d857d0a 100644 (file)
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I$(top_srcdir)/cdirect -I$(top_srcdir)/direct -I$(top_srcdir)/stogo -I$(top_srcdir)/praxis -I$(top_srcdir)/lbfgs -I$(top_srcdir)/luksan -I$(top_srcdir)/crs -I$(top_srcdir)/mlsl -I$(top_srcdir)/mma -I$(top_srcdir)/cobyla -I$(top_srcdir)/newuoa -I$(top_srcdir)/neldermead -I$(top_srcdir)/auglag -I$(top_srcdir)/bobyqa -I$(top_srcdir)/util
+AM_CPPFLAGS = -I$(top_srcdir)/cdirect -I$(top_srcdir)/direct -I$(top_srcdir)/stogo -I$(top_srcdir)/praxis -I$(top_srcdir)/lbfgs -I$(top_srcdir)/luksan -I$(top_srcdir)/crs -I$(top_srcdir)/mlsl -I$(top_srcdir)/mma -I$(top_srcdir)/cobyla -I$(top_srcdir)/newuoa -I$(top_srcdir)/neldermead -I$(top_srcdir)/auglag -I$(top_srcdir)/bobyqa -I$(top_srcdir)/isres -I$(top_srcdir)/util
 
 include_HEADERS = nlopt.h nlopt.f
 noinst_LTLIBRARIES = libapi.la
index 7a621aaff6751529aed820647f0461e30a339dcc..72554556bab6227ce8b7b567daa206e478bfd47a 100644 (file)
@@ -101,6 +101,7 @@ static const char nlopt_algorithm_names[NLOPT_NUM_ALGORITHMS][256] = {
      "Augmented Lagrangian method for equality constraints (local, no-derivative)",
      "Augmented Lagrangian method for equality constraints (local, derivative)",
      "BOBYQA bound-constrained optimization via quadratic models (local, no-derivative)",
+     "ISRES evolutionary constrained optimization (global, no-derivative)",
 };
 
 const char *nlopt_algorithm_name(nlopt_algorithm a)
@@ -224,6 +225,7 @@ static double f_direct(int n, const double *x, int *undefined, void *data_)
 #include "neldermead.h"
 #include "auglag.h"
 #include "bobyqa.h"
+#include "isres.h"
 
 #define AUGLAG_ALG(a) ((a) == NLOPT_LN_AUGLAG ||       \
                       (a) == NLOPT_LN_AUGLAG_EQ ||     \
@@ -295,11 +297,11 @@ static nlopt_result nlopt_minimize_(
 
      /* nonlinear constraints are only supported with some algorithms */
      if (m != 0 && algorithm != NLOPT_LD_MMA && algorithm != NLOPT_LN_COBYLA
-         && !AUGLAG_ALG(algorithm)) 
+         && !AUGLAG_ALG(algorithm) && algorithm != NLOPT_GN_ISRES
          return NLOPT_INVALID_ARGS;
 
      /* nonlinear equality constraints (h(x) = 0) only via some algorithms */
-     if (p != 0 && !AUGLAG_ALG(algorithm))
+     if (p != 0 && !AUGLAG_ALG(algorithm) && algorithm != NLOPT_GN_ISRES)
          return NLOPT_INVALID_ARGS;
 
      d.f = f;
@@ -552,6 +554,13 @@ static nlopt_result nlopt_minimize_(
                                     local_search_alg_deriv,
                                     algorithm == NLOPT_LD_AUGLAG_EQ);
 
+        case NLOPT_GN_ISRES:
+             return isres_minimize(n, f, f_data, 
+                                   m, fc, fc_data, fc_datum_size,
+                                   p, h, h_data, h_datum_size,
+                                   lb, ub, x, minf, &stop,
+                                   0);
+
         default:
              return NLOPT_INVALID_ARGS;
      }
index e434941b456d04bfde41f86d7ab7265d16f0aaba..2e2d38dc004b5f77f77e8908bb9417a030ec6532 100644 (file)
@@ -109,6 +109,8 @@ typedef enum {
 
      NLOPT_LN_BOBYQA,
 
+     NLOPT_GN_ISRES,
+
      NLOPT_NUM_ALGORITHMS /* not an algorithm, just the number of them */
 } nlopt_algorithm;
 
index 6b7fca3872f37df3042b0b62c8ab15b78f7906c8..8aea692522555464b70cd515ae5a391a933fd10c 100644 (file)
@@ -319,6 +319,7 @@ AC_CONFIG_FILES([
    neldermead/Makefile
    auglag/Makefile
    bobyqa/Makefile
+   isres/Makefile
    test/Makefile
 ])
 
diff --git a/isres/Makefile.am b/isres/Makefile.am
new file mode 100644 (file)
index 0000000..d819248
--- /dev/null
@@ -0,0 +1,6 @@
+AM_CPPFLAGS = -I$(top_srcdir)/util -I$(top_srcdir)/api
+
+noinst_LTLIBRARIES = libisres.la
+libisres_la_SOURCES = isres.c isres.h
+
+EXTRA_DIST = README
diff --git a/isres/README b/isres/README
new file mode 100644 (file)
index 0000000..c396213
--- /dev/null
@@ -0,0 +1,23 @@
+This is my implementation of the "Improved Stochastic Ranking
+Evolution Strategy" (ISRES) algorithm for nonlinearly-constrained
+global optimization, based on the method described in:
+
+   Thomas Philip Runarsson and Xin Yao, "Search biases in constrained
+   evolutionary optimization," IEEE Trans. on Systems, Man, and Cybernetics
+   Part C: Applications and Reviews, vol. 35 (no. 2), pp. 233-243 (2005).
+
+It is a refinement of an earlier method described in:
+
+   Thomas P. Runarsson and Xin Yao, "Stochastic ranking for constrained
+   evolutionary optimization," IEEE Trans. Evolutionary Computation,
+   vol. 4 (no. 3), pp. 284-294 (2000).
+
+This is an independent implementation by S. G. Johnson (2009) based
+on the papers above.  Runarsson also has his own Matlab implemention
+available from his web page: http://www3.hi.is/~tpr
+
+It is under the same MIT license as the rest of my code in NLopt (see
+../COPYRIGHT).
+
+Steven G. Johnson
+November 2009
diff --git a/isres/isres.c b/isres/isres.c
new file mode 100644 (file)
index 0000000..e6bf7aa
--- /dev/null
@@ -0,0 +1,246 @@
+/* Copyright (c) 2009 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "isres.h"
+
+/* Improved Stochastic Ranking Evolution Strategy (ISRES) algorithm
+   for nonlinearly-constrained global optimization, based on
+   the method described in:
+
+   Thomas Philip Runarsson and Xin Yao, "Search biases in constrained
+   evolutionary optimization," IEEE Trans. on Systems, Man, and Cybernetics
+   Part C: Applications and Reviews, vol. 35 (no. 2), pp. 233-243 (2005).
+
+   It is a refinement of an earlier method described in:
+
+   Thomas P. Runarsson and Xin Yao, "Stochastic ranking for constrained
+   evolutionary optimization," IEEE Trans. Evolutionary Computation,
+   vol. 4 (no. 3), pp. 284-294 (2000).
+
+   This is an independent implementation by S. G. Johnson (2009) based
+   on the papers above.  Runarsson also has his own Matlab implemention
+   available from his web page: http://www3.hi.is/~tpr
+*/
+
+static int key_compare(void *keys_, const void *a_, const void *b_)
+{
+     const double *keys = (const double *) keys_;
+     const int *a = (const int *) a_;
+     const int *b = (const int *) b_;
+     return keys[*a] < keys[*b] ? -1 : (keys[*a] > keys[*b] ? +1 : 0);
+}
+
+nlopt_result isres_minimize(int n, nlopt_func f, void *f_data,
+                           int m, nlopt_func fc, /* fc <= 0 constraints */
+                           void *fc_data_, ptrdiff_t fc_datum_size,
+                           int p, nlopt_func h, /* h == 0 constraints */
+                           void *h_data_, ptrdiff_t h_datum_size,
+                           const double *lb, const double *ub, /* bounds */
+                           double *x, /* in: initial guess, out: minimizer */
+                           double *minf,
+                           nlopt_stopping *stop,
+                           int population) /* pop. size (= 0 for default) */
+{
+     const double ALPHA = 0.2; /* smoothing factor from paper */
+     const double GAMMA = 0.85; /* step-reduction factor from paper */
+     const double PHI = 1.0; /* expected rate of convergence, from paper */
+     const double PF = 0.45; /* fitness probability, from paper */
+     const double SURVIVOR = 1.0/7.0; /* survivor fraction, from paper */
+     int survivors;
+     nlopt_result ret = NLOPT_SUCCESS;
+     char *fc_data = (char *) fc_data_;
+     char *h_data = (char *) h_data_;
+     double *sigmas = 0, *xs; /* population-by-n arrays (row-major) */
+     double *fval; /* population array of function vals */
+     double *penalty; /* population array of penalty vals */
+     double *x0;
+     int *irank = 0;
+     int k, i, j, c;
+     int mp = m + p;
+     double minf_penalty = HUGE_VAL;
+     double taup, tau;
+
+     if (!population) population = 20 * (n + 1);
+     if (population < 1) return NLOPT_INVALID_ARGS;
+     survivors = ceil(population * SURVIVOR);
+
+     taup = PHI / sqrt(2*n);
+     tau = PHI / sqrt(2*sqrt(n));
+
+     /* we don't handle unbounded search regions */
+     for (j = 0; j < n; ++j) if (nlopt_isinf(lb[j]) || nlopt_isinf(ub[j]))
+                                 return NLOPT_INVALID_ARGS;
+
+     sigmas = (double*) malloc(sizeof(double) * (population*n*2
+                                                + population
+                                                + population
+                                                + n));
+     if (!sigmas) return NLOPT_OUT_OF_MEMORY;
+     xs = sigmas + population*n;
+     fval = xs + population*n;
+     penalty = fval + population;
+     x0 = penalty + population;
+
+     irank = (int*) malloc(sizeof(int) * population);
+     if (!irank) { ret = NLOPT_OUT_OF_MEMORY; goto done; }
+
+     for (k = 0; k < population; ++k) {
+         for (j = 0; j < n; ++j) {
+              sigmas[k*n+j] = (ub[j] - lb[j]) / sqrt(n);
+              xs[k*n+j] = nlopt_urand(lb[j], ub[j]);
+         }
+     }
+     memcpy(xs, x, sizeof(double) * n); /* use input x for xs_0 */
+
+     while (1) { /* each loop body = one generation */
+         int all_feasible = 1;
+
+         /* evaluate f and constraint violations for whole population */
+         for (k = 0; k < population; ++k) {
+              double gval;
+              stop->nevals++;
+              fval[k] = f(n, xs + k*n, NULL, f_data);
+              penalty[k] = 0;
+              for (c = 0; c < m; ++c) { /* inequality constraints */
+                   gval = fc(n, xs + k*n, NULL, 
+                             fc_data + c * fc_datum_size);
+                   if (gval < 0) gval = 0;
+                   penalty[k] += gval*gval;
+              }
+              for (c = m; c < mp; ++c) { /* equality constraints */
+                   gval = h(n, xs + k*n, NULL, 
+                            h_data + (c-m) * h_datum_size);
+                   penalty[k] += gval*gval;
+              }
+              if (penalty[k] > 0) all_feasible = 0;
+
+              /* convergence criteria (FIXME: improve?) */
+
+              if (penalty[k] <= minf_penalty && fval[k] <= *minf
+                  && (penalty[k] != minf_penalty || fval[k] != *minf)) {
+                   if (fval[k] < stop->minf_max && penalty[k] == 0) 
+                        ret = NLOPT_MINF_MAX_REACHED;
+                   else if (nlopt_stop_f(stop, fval[k], *minf)
+                            && nlopt_stop_f(stop, penalty[k], minf_penalty))
+                         ret = NLOPT_FTOL_REACHED;
+                    else if (nlopt_stop_x(stop, xs+k*n, x))
+                        ret = NLOPT_XTOL_REACHED;
+                   memcpy(x, xs+k*n, sizeof(double)*n);
+                   *minf = fval[k];
+                   minf_penalty = penalty[k];
+                   if (ret != NLOPT_SUCCESS) goto done;
+              }
+
+              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;
+         }
+
+         /* "selection" step: rank the population */
+         for (k = 0; k < population; ++k) irank[k] = k;
+         if (all_feasible) /* special case: rank by objective function */
+              nlopt_qsort_r(irank, population, sizeof(int), fval,key_compare);
+         else {
+              /* Runarsson & Yao's stochastic ranking of the population */
+              for (i = 0; i < population; ++i) {
+                   int swapped = 0;
+                   for (j = 0; j < population-1; ++j) {
+                        double u = nlopt_urand(0,1);
+                        if (u < PF || (penalty[irank[j]] == 0
+                                       && penalty[irank[j+1]] == 0)) {
+                             if (fval[irank[j]] > fval[irank[j+1]]) {
+                                  int irankj = irank[j];
+                                  irank[j] = irank[j+1];
+                                  irank[j+1] = irankj;
+                                  swapped = 1;
+                             }
+                        }
+                        else if (penalty[irank[j]] > penalty[irank[j+1]]) {
+                             int irankj = irank[j];
+                             irank[j] = irank[j+1];
+                             irank[j+1] = irankj;
+                             swapped = 1;
+                        }
+                   }
+                   if (!swapped) break;
+              }
+         }
+
+         /* evolve the population:
+            differential evolution for the best survivors,
+            and standard mutation of the best survivors for the rest: */
+         for (k = survivors; k < population; ++k) { /* standard mutation */
+              double taup_rand = taup * nlopt_nrand(0,1);
+              int rk = irank[k], ri;
+              i = k % survivors;
+              ri = irank[i];
+              for (j = 0; j < n; ++j) {
+                   double sigmamax = (ub[j] - lb[j]) / sqrt(n);
+                   sigmas[rk*n+j] = sigmas[ri*n+j] 
+                        * exp(taup_rand + tau*nlopt_nrand(0,1));
+                   if (sigmas[rk*n+j] > sigmamax)
+                        sigmas[rk*n+j] = sigmamax;
+                   do {
+                        xs[rk*n+j] = xs[ri*n+j] 
+                             + sigmas[rk*n+j] * nlopt_nrand(0,1);
+                   } while (xs[rk*n+j] < lb[j] || xs[rk*n+j] > ub[j]);
+                   sigmas[rk*n+j] = sigmas[ri*n+j] + ALPHA*(sigmas[rk*n+j]
+                                                          - sigmas[ri*n+j]);
+              }
+         }
+         memcpy(x0, xs, n * sizeof(double));
+         for (k = 0; k+1 < survivors; ++k) { /* differential variation */
+              int rk = irank[k];
+              for (j = 0; j < n; ++j)
+                   xs[rk*n+j] += GAMMA * (x0[j] - xs[(k+1)*n+j]);
+         }
+         /* standard mutation for last survivor and for any
+            survivor components that are now outside the bounds */
+         for (k = 0; k < survivors; ++k) {
+              double taup_rand = taup * nlopt_nrand(0,1);
+              int rk = irank[k];
+              for (j = 0; j < n; ++j) if (k == survivors - 1
+                                          || xs[rk*n+j] < lb[j]
+                                          || xs[rk*n+j] > ub[j]) {
+                   double sigmamax = (ub[j] - lb[j]) / sqrt(n);
+                   double xi = xs[rk*n+j];
+                   double sigi = sigmas[rk*n+j];
+                   sigmas[rk*n+j] *= exp(taup_rand + tau*nlopt_nrand(0,1));
+                   if (sigmas[rk*n+j] > sigmamax)
+                        sigmas[rk*n+j] = sigmamax;
+                   do {
+                        xs[rk*n+j] = xi + sigmas[rk*n+j] * nlopt_nrand(0,1);
+                   } while (xs[rk*n+j] < lb[j] || xs[rk*n+j] > ub[j]);
+                   sigmas[rk*n+j] = sigi + ALPHA * (sigmas[rk*n+j] - sigi);
+              }
+         }
+     }
+
+done:
+     if (irank) free(irank);
+     if (sigmas) free(sigmas);
+     return ret;
+}
diff --git a/isres/isres.h b/isres/isres.h
new file mode 100644 (file)
index 0000000..bd506fa
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (c) 2007-2008 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ */
+
+#ifndef ISRES_H
+#define ISRES_H
+
+#include "nlopt.h"
+#include "nlopt-util.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+nlopt_result isres_minimize(int n, nlopt_func f, void *f_data,
+                           int m, nlopt_func fc, /* fc <= 0 constraints */
+                           void *fc_data_, ptrdiff_t fc_datum_size,
+                           int p, nlopt_func h, /* h == 0 constraints */
+                           void *h_data_, ptrdiff_t h_datum_size,
+                           const double *lb, const double *ub, /* bounds */
+                           double *x, /* in: initial guess, out: minimizer */
+                           double *minf,
+                           nlopt_stopping *stop,
+                           int population); /* init. population */
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif /* __cplusplus */
+
+#endif
+
index 2e82376b98e0a29d5e51f89264193046c1b815cb..54851294d07544e35a76b0f710097680bf06d3c1 100644 (file)
@@ -10,7 +10,8 @@
 
    Modified 2007 by Steven G. Johnson for use with NLopt (to avoid
    namespace pollution, use uint32_t instead of unsigned long,
-   and add the urand function).
+   and add the urand function).  Modified 2009 to add normal-distributed
+   random numbers.
 
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
 
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+   OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
    Any feedback is very welcome.
@@ -206,6 +208,26 @@ int nlopt_iurand(int n)
      return(nlopt_genrand_int32() % n);
 }
 
+/* normal-distributed random numbers with the given mean and std. deviation,
+   added by SGJ */
+double nlopt_nrand(double mean, double stddev)
+{
+  // Box-Muller algorithm to generate Gaussian from uniform
+  // see Knuth vol II algorithm P, sec. 3.4.1
+  double v1, v2, s;
+  do {
+    v1 = nlopt_urand(-1, 1);
+    v2 = nlopt_urand(-1, 1);
+    s = v1*v1 + v2*v2;
+  } while (s >= 1.0);
+  if (s == 0) {
+    return mean;
+  }
+  else {
+    return mean + v1 * sqrt(-2 * log(s) / s) * stddev;
+  }
+}
+
 #if 0
 #include <stdio.h>
 int main(void)
index 7a1875b3695e125887914de85a72dc93364d82ea..861914df353e1c47ac1e1301014d38b24a9189aa 100644 (file)
@@ -52,6 +52,7 @@ extern unsigned long nlopt_time_seed(void);
 extern void nlopt_init_genrand(unsigned long s);
 extern double nlopt_urand(double a, double b);
 extern int nlopt_iurand(int n);
+extern double nlopt_nrand(double mean, double stddev);
 
 /* Sobol' low-discrepancy-sequence generation */
 typedef struct nlopt_soboldata_s *nlopt_sobol;