最適化(シンプレックス法)

mskefile,データ例,プログラム

-------------------------i_data-------------------------

					// 関数 a
関数 1 変数の数 2 最大試行回数 1000 初期値設定係数 1.0
許容誤差 1.0e-20 縮小比率 0.7 拡大比率 1.5
初期値 0.0 0.0
					// 関数 b
関数 2 変数の数 2 最大試行回数 1000 初期値設定係数 1.0
許容誤差 1.0e-20 縮小比率 0.7 拡大比率 1.5
初期値 0.0 0.0
					// 関数 c
関数 3 変数の数 2 最大試行回数 1000 初期値設定係数 1.0
許容誤差 1.0e-20 縮小比率 0.7 拡大比率 1.5
初期値 0.0 0.0

-------------------------program-------------------------

/**************************************/
/* シンプレックス法による最小値の計算 */
/*      coded by Y.Suganuma           */
/**************************************/
#include <stdio.h>

double snx1(double *);
double snx2(double *);
double snx3(double *);
int simplex(int, int, double, double, double, double, double *, double *, double (*)(double *));

int main()
{
	double eps, r1, r2, *x, y, k;
	int fun, i1, max, n, sw = 0;
					// データの入力
	scanf("%*s %d %*s %d %*s %d %*s %lf", &fun, &n, &max, &k);
	scanf("%*s %lf %*s %lf %*s %lf", &eps, &r1, &r2);
	x = new double [n];
	scanf("%*s");
	for (i1 = 0; i1 < n; i1++)
		scanf("%lf", &x[i1]);
					// 実行
	switch (fun) {
		case 1:
			sw = simplex(max, n, k, eps, r1, r2, &y, x, snx1);
			break;
		case 2:
			sw = simplex(max, n, k, eps, r1, r2, &y, x, snx2);
			break;
		case 3:
			sw = simplex(max, n, k, eps, r1, r2, &y, x, snx3);
			break;
	}
					// 結果の出力
	if (sw < 0)
		printf("   収束しませんでした!");
	else {
		printf("   結果=");
		for (i1 = 0; i1 < n; i1++)
			printf("%f ", x[i1]);
		printf(" 最小値=%f  回数=%d\n", y, sw);
	}

	delete [] x;

	return 0;
}

/******************************************/
/* シンプレックス法                       */
/*      max : 最大繰り返し回数            */
/*      n : 次元                          */
/*      k : 初期値設定係数                */
/*      r1 : 縮小比率                     */
/*      r2 : 拡大比率                     */
/*      y : 最小値                        */
/*      x : x(初期値と答え)               */
/*      snx : 関数値を計算する関数名      */
/*      return : >=0 : 正常終了(収束回数) */
/*               =-1 : 収束せず           */
/******************************************/
#include <math.h>

int simplex(int max, int n, double k, double eps, double r1, double r2, double *y, double *x, double (*snx)(double *))
{
	double **xx, *yy, *xg, *xr, *xn, yr, yn, e;
	int i1, i2, fh = -1, fg = -1, fl = -1, count = 0, sw = -1;
					// 初期値の設定
	yy = new double [n+1];
	xg = new double [n];
	xr = new double [n];
	xn = new double [n];
	xx = new double * [n+1];
	for (i1 = 0; i1 < n+1; i1++)
		xx[i1] = new double [n];
	for (i1 = 0; i1 < n+1; i1++) {
		for (i2 = 0; i2 < n; i2++)
			xx[i1][i2] = x[i2];
		if (i1 > 0)
			xx[i1][i1-1] += k;
		yy[i1] = snx(xx[i1]);
	}
					// 最大値,最小値の計算
	for (i1 = 0; i1 < n+1; i1++) {
		if (fh < 0 || yy[i1] > yy[fh])
			fh = i1;
		if (fl < 0 || yy[i1] < yy[fl])
			fl = i1;
	}
	for (i1 = 0; i1 < n+1; i1++) {
		if (i1 != fh && (fg < 0 || yy[i1] > yy[fg]))
			fg = i1;
	}
					// 最小値の計算
	while (count < max && sw < 0) {
		count++;
							// 重心の計算
		for (i1 = 0; i1 < n; i1++)
			xg[i1] = 0.0;
		for (i1 = 0; i1 < n+1; i1++) {
			if (i1 != fh) {
				for (i2 = 0; i2 < n; i2++)
					xg[i2] += xx[i1][i2];
			}
		}
		for (i1 = 0; i1 < n; i1++)
			xg[i1] /= n;
							// 最大点の置き換え
		for (i1 = 0; i1 < n; i1++)
			xr[i1] = 2.0 * xg[i1] - xx[fh][i1];
		yr = snx(xr);
		if (yr >= yy[fh]) {   // 縮小
			for (i1 = 0; i1 < n; i1++)
				xr[i1] = (1.0 - r1) * xx[fh][i1] + r1 * xr[i1];
			yr = snx(xr);
		}
		else if (yr < (yy[fl]+(r2-1.0)*yy[fh])/r2) {   // 拡大
			for (i1 = 0; i1 < n; i1++)
				xn[i1] = r2 * xr[i1] - (r2 - 1.0) * xx[fh][i1];
			yn = snx(xn);
			if (yn <= yr) {
				for (i1 = 0; i1 < n; i1++)
					xr[i1] = xn[i1];
				yr = yn;
			}
		}
		for (i1 = 0; i1 < n; i1++)
			xx[fh][i1] = xr[i1];
		yy[fh] = yr;
							// シンプレックス全体の縮小
		if (yy[fh] >= yy[fg]) {
			for (i1 = 0; i1 < n+1; i1++) {
				if (i1 != fl) {
					for (i2 = 0; i2 < n; i2++)
						xx[i1][i2] = 0.5 * (xx[i1][i2] + xx[fl][i2]);
					yy[i1] = snx(xx[i1]);
				}
			}
		}
							// 最大値,最小値の計算
		fh = -1;
		fg = -1;
		fl = -1;
		for (i1 = 0; i1 < n+1; i1++) {
			if (fh < 0 || yy[i1] > yy[fh])
				fh = i1;
			if (fl < 0 || yy[i1] < yy[fl])
				fl = i1;
		}
		for (i1 = 0; i1 < n+1; i1++) {
			if (i1 != fh && (fg < 0 || yy[i1] > yy[fg]))
				fg = i1;
		}
							// 収束判定
		e = 0.0;
		for (i1 = 0; i1 < n+1; i1++) {
			if (i1 != fl) {
				yr  = yy[i1] - yy[fl];
				e  += yr * yr;
			}
		}
		if (e < eps)
			sw = 0;
	}

	if (sw == 0) {
		sw = count;
		*y = yy[fl];
		for (i1 = 0; i1 < n; i1++)
			x[i1] = xx[fl][i1];
	}

	delete [] yy;
	delete [] xg;
	delete [] xr;
	delete [] xn;
	for (i1 = 0; i1 < n+1; i1++)
		delete [] xx[i1];
	delete [] xx;

	return sw;
}

/*******************/
/* 関数値の計算    */
/*      y = f(x)   */
/*      return : y */
/*******************/
					// 関数1
double snx1(double *x)
{
	double x1, y1, y;

	x1 = x[0] - 1.0;
	y1 = x[1] - 2.0;
	y  = x1 * x1 + y1 * y1;

	return y;
}
					// 関数2
double snx2(double *x)
{
	double x1, y1, y;

	x1 = x[1] - x[0] * x[0];
	y1 = 1.0 - x[0];
	y  = 100.0 * x1 * x1 + y1 * y1;

	return y;
}
					// 関数3
double snx3(double *x)
{
	double x1, y1, z1, y;

	x1 = 1.5 - x[0] * (1.0 - x[1]);
	y1 = 2.25 - x[0] * (1.0 - x[1] * x[1]);
	z1 = 2.625 - x[0] * (1.0 - x[1] * x[1] * x[1]);
	y  = x1 * x1 + y1 * y1 + z1 * z1;

	return y;
}