| nmsimplex.cpp.html | mathcode2html |
| Source file: nmsimplex.cpp | |
| Converted: Mon Jul 8 2013 at 14:04:42 | |
| This documentation file will not reflect any later changes in the source file. |
$$\phantom{******** If you see this on the webpage then the
browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root
is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$
$$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$
$$\newcommand{\A}{{\cal A}}$$
$$\newcommand{\W}{{\cal W}}$$
/*
* Program: nmsimplex.c
* Author : Michael F. Hutt
* http://www.mikehutt.com
* 11/3/97
* $Id: nmsimplex.c,v 1.2 2007/07/23 13:46:38 mike Exp $
*
* gcc -Wall -o nmsimplex nmsimplex.c -lm
*
* An implementation of the Nelder-Mead simplex method applied to
* Rosenbrock's function.
*
* Copyright (c) 1997-2007 <Michael F. Hutt>
*
* 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.
*
*
* Jan. 6, 1999
* Modified to conform to the algorithm presented
* in Margaret H. Wright's paper on Direct Search Methods.
*
* Jul. 23, 2007
* Fixed memory leak.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "nmsimplex.h"
//define MAX_IT 1000 /* maximum number of iterations */
#define ALPHA 1.0 /* reflection coefficient */
#define BETA 0.5 /* contraction coefficient */
#define GAMMA 2.0 /* expansion coefficient */
double rosen(double x[])
{
return (100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0])+(1.0-x[0])*(1.0-x[0]));
}
extern "C" QUBFAST_API double simplex(double (*func)(void*, double[]), void *obj, double start[],int n, double EPSILON, double scale, int MAX_IT)
{
int vs; /* vertex with smallest value */
int vh; /* vertex with next smallest value */
int vg; /* vertex with largest value */
int i,j,m,row;
int k; /* track the number of function evaluations */
int itr; /* track the number of iterations */
double **v; /* holds vertices of simplex */
double pn,qn; /* values used to create initial simplex */
double *f; /* value of function at each vertex */
double fr; /* value of function at reflection point */
double fe; /* value of function at expansion point */
double fc; /* value of function at contraction point */
double *vr; /* reflection - coordinates */
double *ve; /* expansion - coordinates */
double *vc; /* contraction - coordinates */
double *vm; /* centroid - coordinates */
double min;
double fsum,favg,s,cent;
/* dynamically allocate arrays */
/* allocate the rows of the arrays */
v = (double **) malloc ((n+1) * sizeof(double *));
f = (double *) malloc ((n+1) * sizeof(double));
vr = (double *) malloc (n * sizeof(double));
ve = (double *) malloc (n * sizeof(double));
vc = (double *) malloc (n * sizeof(double));
vm = (double *) malloc (n * sizeof(double));
/* allocate the columns of the arrays */
for (i=0;i<=n;i++) {
v[i] = (double *) malloc (n * sizeof(double));
}
/* create the initial simplex */
/* assume one of the vertices is 0,0 */
pn = scale*(sqrt((double)(n+1))-1+n)/(n*sqrt(2.0));
qn = scale*(sqrt((double)(n+1))-1)/(n*sqrt(2.0));
for (i=0;i<n;i++) {
v[0][i] = start[i];
}
for (i=1;i<=n;i++) {
for (j=0;j<n;j++) {
if (i-1 == j) {
v[i][j] = pn + start[j];
}
else {
v[i][j] = qn + start[j];
}
}
}
/* find the initial function values */
for (j=0;j<=n;j++) {
f[j] = func(obj, v[j]);
}
k = n+1;
/* print out the initial values */
//printf("Initial Values\n");
//for (j=0;j<=n;j++) {
// printf("%f %f %f\n",v[j][0],v[j][1],f[j]);
//}
/* begin the main loop of the minimization */
for (itr=1;itr<=MAX_IT;itr++) {
/* find the index of the largest value */
vg=0;
for (j=0;j<=n;j++) {
if (f[j] > f[vg]) {
vg = j;
}
}
/* find the index of the smallest value */
vs=0;
for (j=0;j<=n;j++) {
if (f[j] < f[vs]) {
vs = j;
}
}
/* find the index of the second largest value */
vh=vs;
for (j=0;j<=n;j++) {
if (f[j] > f[vh] && f[j] < f[vg]) {
vh = j;
}
}
/* calculate the centroid */
for (j=0;j<=n-1;j++) {
cent=0.0;
for (m=0;m<=n;m++) {
if (m!=vg) {
cent += v[m][j];
}
}
vm[j] = cent/n;
}
/* reflect vg to new vertex vr */
for (j=0;j<=n-1;j++) {
/*vr[j] = (1+ALPHA)*vm[j] - ALPHA*v[vg][j];*/
vr[j] = vm[j]+ALPHA*(vm[j]-v[vg][j]);
}
fr = func(obj, vr);
k++;
if (fr < f[vh] && fr >= f[vs]) {
for (j=0;j<=n-1;j++) {
v[vg][j] = vr[j];
}
f[vg] = fr;
}
/* investigate a step further in this direction */
if ( fr < f[vs]) {
for (j=0;j<=n-1;j++) {
/*ve[j] = GAMMA*vr[j] + (1-GAMMA)*vm[j];*/
ve[j] = vm[j]+GAMMA*(vr[j]-vm[j]);
}
fe = func(obj, ve);
k++;
/* by making fe < fr as opposed to fe < f[vs],
Rosenbrocks function takes 63 iterations as opposed
to 64 when using double variables. */
if (fe < fr) {
for (j=0;j<=n-1;j++) {
v[vg][j] = ve[j];
}
f[vg] = fe;
}
else {
for (j=0;j<=n-1;j++) {
v[vg][j] = vr[j];
}
f[vg] = fr;
}
}
/* check to see if a contraction is necessary */
if (fr >= f[vh]) {
if (fr < f[vg] && fr >= f[vh]) {
/* perform outside contraction */
for (j=0;j<=n-1;j++) {
/*vc[j] = BETA*v[vg][j] + (1-BETA)*vm[j];*/
vc[j] = vm[j]+BETA*(vr[j]-vm[j]);
}
fc = func(obj, vc);
k++;
}
else {
/* perform inside contraction */
for (j=0;j<=n-1;j++) {
/*vc[j] = BETA*v[vg][j] + (1-BETA)*vm[j];*/
vc[j] = vm[j]-BETA*(vm[j]-v[vg][j]);
}
fc = func(obj, vc);
k++;
}
if (fc < f[vg]) {
for (j=0;j<=n-1;j++) {
v[vg][j] = vc[j];
}
f[vg] = fc;
}
/* at this point the contraction is not successful,
we must halve the distance from vs to all the
vertices of the simplex and then continue.
10/31/97 - modified to account for ALL vertices.
*/
else {
for (row=0;row<=n;row++) {
if (row != vs) {
for (j=0;j<=n-1;j++) {
v[row][j] = v[vs][j]+(v[row][j]-v[vs][j])/2.0;
}
}
}
f[vg] = func(obj, v[vg]);
k++;
f[vh] = func(obj, v[vh]);
k++;
}
}
/* print out the value at each iteration */
//printf("Iteration %d\n",itr);
//for (j=0;j<=n;j++) {
// printf("%f %f %f\n",v[j][0],v[j][1],f[j]);
//}
/* test for convergence */
fsum = 0.0;
for (j=0;j<=n;j++) {
fsum += f[j];
}
favg = fsum/(n+1);
s = 0.0;
for (j=0;j<=n;j++) {
s += pow((f[j]-favg),2.0)/(n);
}
s = sqrt(s);
if (s < EPSILON) break;
}
/* end main loop of the minimization */
/* find the index of the smallest value */
vs=0;
for (j=0;j<=n;j++) {
if (f[j] < f[vs]) {
vs = j;
}
}
//printf("The minimum was found at\n");
for (j=0;j<n;j++) {
//printf("%e\n",v[vs][j]);
start[j] = v[vs][j];
}
min=func(obj, v[vs]);
k++;
//printf("%d Function Evaluations\n",k);
//printf("%d Iterations through program\n",itr);
free(f);
free(vr);
free(ve);
free(vc);
free(vm);
for (i=0;i<=n;i++) {
free (v[i]);
}
free(v);
return min;
}
/*
int main()
{
double start[] = {-1.2,1.0};
double min;
int i;
min=simplex(rosen,start,2,1.0e-4,1);
for (i=0;i<2;i++) {
printf("%f\n",start[i]);
}
return 0;
}
*/