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;
}
*/