You are on page 1of 12

外罚函数法_21215764 郭洁榕

一、题目:

其中,第(4)题省略

二、思路

三、迭代过程及数值模拟结果:

第一题:
最小值点坐标为:(1,2)
最小值为:xmin=-12
第二题
第三题
四、计算检验
五、代码及注释

//######################################################################
//中山大学航空航天学院
//最优化作业习题外罚函数法 21215764
//======================================================================
//姓名: 郭洁榕
//邮箱: guojr26@mail2.sysu.edu.cn
//日期: 2022 年 6 月 23 日
// ======================================================================
//功能:外罚函数法算法求解约束问题:min f(x)
//输入:fun 是目标函数,strain 为约束条件函数
// epsilon 是约束裕量
//输出:极小值点坐标,x,val 分别是近似最优点和最优值(符号与书上保持一致)
//#######################################################################
#include<iostream>
using namespace std;
#include<math.h>

const int kkg = 2;


const int qkg = 1;
double r0;

//1、目标函数
double fun(double x[])
{
double fun0;
//第二、三题
fun0 = pow(x[0] , 2) + pow(x[1] , 2);
//第一题
//fun0 = -x[0] - x[1];
return(fun0);
}

//2、约束条件
void strain(double x[], double g[])
{
double epsilon = 0.000001;//约束裕量为 0.0001,将不等式约束转化为等式
//不等式约束条件
g[0] = 2*x[0] + x[1]-2+ epsilon;
g[1] = x[0] - 1 - epsilon;
//等式约束条件
//g[2] = 1 - pow(x[0], 1) - pow(x[1], 1);
}

//3、罚函数
double fahanshu(double p[])
{
int i;
double fun1, sg, * g;

g = (double*)malloc((kkg + qkg) * sizeof(double));


sg = 0;
strain(p, g);//约束条件

for (i = 0; i < kkg; i++)


if (*(g + i) < 0)
sg = sg + pow((*(g + i)), 2);
if (qkg != 0)
for (i = kkg; i < kkg + qkg; i++)
sg = sg + pow((*(g + i)), 2);
free(g);

fun1 = fun(p) + r0 * sg;//罚函数由原目标函数和惩罚项组成


return(fun1);
}

void jtf(double x0[], double h0, double s[], int n, double a[], double b[])//多维进退法
程序
{
int i;
double* x[3], h, f1, f2, f3;
for (i = 0; i < 3; i++)
x[i] = (double*)malloc(n * sizeof(double));
h = h0;
for (i = 0; i < n; i++)
*(x[0] + i) = x0[i];
f1 = fahanshu(x[0]);//求 x[0]点的函数值
for (i = 0; i < n; i++)
*(x[1] + i) = *(x[0] + i) + h * s[i];
f2 = fahanshu(x[1]);//求 x[1]点的函数值
if (f2 >= f1)//如果 f2>=f1,换向搜索
{
h = -h0;
for (i = 0; i < n; i++)
*(x[2] + i) = *(x[0] + i);
f3 = f1;
for (i = 0; i < n; i++)
{
*(x[0] + i) = *(x[1] + i);
*(x[1] + i) = *(x[2] + i);
}
f1 = f2;
f2 = f3;
}
for (;;)
{
h = 2 * h;//如果 f2<f1,则加大步幅
for (i = 0; i < n; i++)
*(x[2] + i) = *(x[1] + i) + h * s[i];
f3 = fahanshu(x[2]);
if (f2 < f3) break;
else
{
for (i = 0; i < n; i++)
{
*(x[0] + i) = *(x[1] + i);
*(x[1] + i) = *(x[2] + i);
}
f1 = f2;
f2 = f3;
}
}
if (h < 0)
for (i = 0; i < n; i++)
{
a[i] = *(x[2] + i);
b[i] = *(x[0] + i);
}
else
for (i = 0; i < n; i++)
{
a[i] = *(x[0] + i);
b[i] = *(x[2] + i);
}
for (i = 0; i < 3; i++)
free(x[i]);//初步确定搜索区间 a,b
}
double gold(double a[], double b[], double eps, int n, double xx[])//多维黄金分割法程序
{
int i;
double f1, f2, * x[2], fun3, q, w;
for (i = 0; i < 2; i++)
x[i] = (double*)malloc(n * sizeof(double));
for (i = 0; i < n; i++)
{
*(x[0] + i) = a[i] + 0.618 * (b[i] - a[i]);
*(x[1] + i) = a[i] + 0.382 * (b[i] - a[i]);
}
f1 = fahanshu(x[0]);
f2 = fahanshu(x[1]);
do
{
if (f1 > f2)
{
for (i = 0; i < n; i++)
{
b[i] = *(x[0] + i);
*(x[0] + i) = *(x[1] + i);
}
f1 = f2;
for (i = 0; i < n; i++)
*(x[1] + i) = a[i] + 0.382 * (b[i] - a[i]);
f2 = fahanshu(x[1]);
}
else
{
for (i = 0; i < n; i++)
{
a[i] = *(x[1] + i);
*(x[1] + i) = *(x[0] + i);
}
f2 = f1;
for (i = 0; i < n; i++)
*(x[0] + i) = a[i] + 0.618 * (b[i] - a[i]);
f1 = fahanshu(x[0]);
}
q = 0;
for (i = 0; i < n; i++)
q = q + (b[i] - a[i]) * (b[i] - a[i]);
w = sqrt(q);
} while (w > eps);
for (i = 0; i < n; i++)
xx[i] = 0.5 * (a[i] + b[i]);//极小值点 0.5*(a[i]+b[i])
fun3 = fahanshu(xx);
for (i = 0; i < 2; i++)
free(x[i]);
return(fun3);//返回极小值点处的函数值
}

double oneoptim(double x0[], double s[], double h0, double epsg, int n, double x[])
{
double* a, * b, fun4;
a = (double*)malloc(n * sizeof(double));
b = (double*)malloc(n * sizeof(double));
jtf(x0, h0, s, n, a, b);//调用进退法程序
fun4 = gold(a, b, epsg, n, x);//调用黄金分割法程序,求的极小值
free(a);
free(b);
return (fun4);
}

double powell(double p[], double h0, double eps, double epsg, int n, double x[])//鲍威
尔法求出极小值
{
int i, j, m;
double* xx[4], * ss, * s;
double f, f0, f1, f2, f3, fx, epsilon, df, sdx, q, d;
ss = (double*)malloc(n * (n + 1) * sizeof(double));
s = (double*)malloc(n * sizeof(double));
for (i = 0; i < n; i++)
{
for (j = 0; j <= n; j++)
*(ss + i * (n + 1) + j) = 0;
*(ss + i * (n + 1) + i) = 1;
}//初始化方向,n 个线性无关的量
for (i = 0; i < 4; i++)
xx[i] = (double*)malloc(n * sizeof(double));
for (i = 0; i < n; i++)
*(xx[0] + i) = p[i];
for (;;) //计算初始点和终点的函数值
{
for (i = 0; i < n; i++)
{
*(xx[1] + i) = *(xx[0] + i);
x[i] = *(xx[1] + i);
}
f0 = f1 = fahanshu(x);
epsilon = -1;
for (j = 0; j < n; j++)
{
for (i = 0; i < n; i++)
{
*(xx[0] + i) = x[i];
*(s + i) = *(ss + i * (n + 1) + j);
}
f = oneoptim(xx[0], s, h0, epsg, n, x);//进入一元优化程序,开始新的一轮搜索,
获得极小值点
df = f0 - f;
if (df > epsilon)
{
epsilon = df;
m = j;
}
}//求函数值之差得最大值
sdx = 0;
for (i = 0; i < n; i++)
sdx = sdx + fabs(x[i] - (*(xx[1] + i)));
if (sdx < eps)
{

free(ss);
free(s);
for (i = 0; i < 4; i++)
free(xx[i]);
return(f);
}
for (i = 0; i < n; i++)
*(xx[2] + i) = x[i];
f2 = f;
for (i = 0; i < n; i++)
{
*(xx[3] + i) = 2 * (*(xx[2] + i) - (*(xx[1] + i)));//计算反射点
x[i] = *(xx[3] + i);
}
fx = fahanshu(x);//计算反射点的函数值
f3 = fx;
q = (f1 - 2 * f2 + f3) * (f1 - f2 - epsilon) * (f1 - f2 - epsilon);
d = 0.5 * epsilon * (f1 - f3) * (f1 - f3);
if ((f3 < f1) || (q < d))//鲍威尔法判别条件
{
if (f2 <= f3)
for (i = 0; i < n; i++)
*(xx[0] + i) = *(xx[2] + i);
else
for (i = 0; i < n; i++)
*(xx[0] + i) = *(xx[3] + i);
}
else
{
for (i = 0; i < n; i++)
{
*(ss + (i + 1) * (n + 1)) = x[i] - (*(xx[1] + i));
*(s + i) = *(ss + (i + 1) * (n + 1));//满足判别条件,进行替换;若不满足,
仍用原方向
}
f = oneoptim(xx[0], s, h0, epsg, n, x);//开始新的一轮搜索
for (i = 0; i < n; i++)
*(xx[0] + i) = x[i];
for (j = m + 1; j <= n; j++)
for (i = 0; i < n; i++)
*(ss + i * (n + 1) + j - 1) = *(ss + i * (n + 1) + j);
}
}
}

void main()
{
int i;
double p[] = { 7,8 };
double initialP, val, e, x[2];

e = 20;//罚因子递增系数 e 取 10
r0 = 0.1;//初始罚因子
initialP = 10;//初始点取为 10

do
{
val = powell(p, 0.1, 0.0001, 0.0001, 2, x);//用无约束算法,求出极值点,步长 0.1,
精度 0.0001,
if (fabs(initialP - val) <= 0.0001) //按中止准则判别,若满足则输出最优解,
停止计算
{
cout << "最优点及其目标函数值为:" << endl;
cout << "x[0]=" << x[0] << ";x[1]=" << x[1] << endl;
cout << "目标函数极小值为:" << endl;
cout << val << endl;

return;
}
else
{
//输出迭代过程
cout << "当前迭代最优点及其目标函数值为:" << endl;
cout << "x[0]=" << x[0] << ";x[1]=" << x[1] << endl;
cout << "当前迭代目标函数极小值为:" << endl;
cout << val << endl;
initialP = val;
r0 = e * r0;//增大惩罚因子
for (i = 0; i < 2; i++)
{
*(p + i) = x[i];
}

} while (1);

system("pause");
}

You might also like