复合形法求解约束优化问题

复合形法求解约束优化问题

cs.c

/**
 * @file cs.c
 * @author zhn
 * @brief
 * @version 0.1
 * @date 2022-10-24
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "cs.h"
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#define bool _Bool
#define N 2
#define EDGENUMBER 2 * N
#define alpha 1.3
#define beta 0.5
#define delta 1e-5
#define ksi 10e-5

/**
 * @brief 该结构体存储了k个顶点对应的坐标和函数值
 *
 */
struct initStruct
{
    
    
    double x[N];
    double fx;
} initstrcut[EDGENUMBER];

double a[N] = {
    
    0, 0};
double b[N] = {
    
    6, 8};
// double a[N] = {2, 0.5};
// double b[N] = {4, 1};

double xh[N];
double xg[N];
double xl[N];
/// @brief 所有可行点的形心
double xi[N];
/// @brief 除了最差点xh之外其他点的形心
double xc[N];
/// @brief 反射点xr
double xr[N];

extern void sayCS();
static double f(double *x);
static bool isInRange(double *x);
static int edgeNumber();
static int cmp(const void *_a, const void *_b);
static bool isAllInRange(struct initStruct *Struct, int k);
static double getRandomR();
static double getInitRandomX(int i);
static void getXi(struct initStruct *Struct, int k);
static void getXc(struct initStruct *Struct, int k);
static void getXr();
static void update(struct initStruct *Struct, int k);
static void init(struct initStruct *Struct, int k);
static void getFx(struct initStruct *Struct, int k);
static void updateXc();
static double max(double a, double b);
static double min(double a, double b);
static bool isConvergence(struct initStruct *Struct, int k);
static void updateXh(struct initStruct *Struct, int k);
static void iterate(struct initStruct *Struct, int k);
static void swap_arr(double *arr_a, double *arr_b);
extern void CS();

void CS()
{
    
    
    sayCS();

    int k = edgeNumber();
    do
    {
    
    
        init(initstrcut, k);
        initstrcut[0].x[0] = 2;
        initstrcut[0].x[1] = 1;
        while (!(isAllInRange(initstrcut, k)))
        {
    
    
            update(initstrcut, k);
        }
        //        initstrcut[0].x[0] = 2;
        //        initstrcut[0].x[1] = 2;
        //        initstrcut[1].x[0] = 4;
        //        initstrcut[1].x[1] = 2;
        //        initstrcut[2].x[0] = 2;
        //        initstrcut[2].x[1] = 4;
        //        initstrcut[3].x[0] = 4;
        //        initstrcut[3].x[1] = 4;
        getXi(initstrcut, k);
        getFx(initstrcut, k);
        qsort(initstrcut, EDGENUMBER, sizeof(struct initStruct), cmp);
        printf("初始化之后的结果如下:\n");
        for (int i = 0; i < k; i++)
        {
    
    
            for (int j = 0; j < N; j++)
            {
    
    
                printf("initstruct[%d].x[%d] = %f  ", i, j, initstrcut[i].x[j]);
            }
            printf("\nfx[%d] = %f\n", i, initstrcut[i].fx);
        }
        memcpy(xl, initstrcut[0].x, sizeof(xl));
        memcpy(xh, initstrcut[k - 1].x, sizeof(xh));
        memcpy(xg, initstrcut[k - 2].x, sizeof(xg));
        printf("初始化后的最好点、最差点和次差点分别是:\n");
        for (int i = 0; i < N; i++)
        {
    
    
            printf("xl[%d] = %f\n", i, xl[i]);
            printf("xh[%d] = %f\n", i, xh[i]);
            printf("xg[%d] = %f\n", i, xg[i]);
        }
        getXc(initstrcut, k);
        if (!(isInRange(xc)))
        {
    
    
            updateXc();
        }
    } while (!(isInRange(xc)));
    getXr();
    printf("初始化完成,下面进行迭代操作:\n");
    int iterateTimes = 0;
    while (!isConvergence(initstrcut, k))
    {
    
    
        iterateTimes++;
        printf("这是初始化后的第%d次迭代:\n", iterateTimes);
        updateXh(initstrcut, k);
    }
    qsort(initstrcut, EDGENUMBER, sizeof(struct initStruct), cmp);
    printf("优化的最终结果为:\n");
    for (int i = 0; i < N; i++)
    {
    
    
        printf("x[%d] = %f\n", i, initstrcut[0].x[i]);
    }
    getFx(initstrcut, k);
    printf("函数的最优解fx = %f\n", initstrcut[0].fx);
}

/**
 * @brief 目标函数
 *
 * @param x
 * @return double
 */
static double f(double *x)
{
    
    
    return (pow(x[0], 2) + pow(x[1], 2) - x[0] * x[1] - 10 * x[0] - 4 * x[1] + 60);
}
// static double f(double *x)
// {
    
    
//     return (25 / (x[0] * pow(x[1], 3)));
// }
/**
 * @brief 判断当前点是否符合约束条件
 *
 * @param x1
 * @param x2
 * @return true
 * @return false
 */
static bool isInRange(double *x)
{
    
    
    bool flag;
    if ((x[0] >= 0) && (x[1] >= 0) && (x[0] <= 6) && (x[1] <= 8) && (x[0] + x[1]) <= 11)
    {
    
    
        flag = true;
    }
//     if ((x[0] >= 2) && (x[1] >= 0.5) && (x[0] <= 4) && (x[1] <= 1) && (x[0] * x[1] <= 2.5) && (x[0] * pow(x[1], 2)) >= 0.6)
//     {
    
    
//         flag = true;
//     }
    else
    {
    
    
        flag = false;
    }
    return flag;
}
/**
 * @brief 计算复合形的边数
 *
 * @return int
 */
static int edgeNumber()
{
    
    
    int edgeNumber;
    if (N <= 5)
    {
    
    
        edgeNumber = 2 * N;
    }
    else if (N > 5)
    {
    
    
        edgeNumber = N + 1;
    }
    return edgeNumber;
}
/**
 * @brief qsort函数的比较函数,使qsort函数从小到大排列
 *
 * @param _a
 * @param _b
 * @return int
 */
static int cmp(const void *_a, const void *_b)
{
    
    
    return (*(struct initStruct *)_a).fx > (*(struct initStruct *)_b).fx ? 1 : -1;
}
/**
 * @brief 判断结构体里面所有的k个顶点是否都在可行域内
 *
 * @param Struct
 * @param k
 * @return true
 * @return false
 */
static bool isAllInRange(struct initStruct *Struct, int k)
{
    
    
    bool flag = true;
    for (int i = 0; i < k; i++)
    {
    
    
        if (!(isInRange(Struct[i].x)))
        {
    
    
            flag = false;
        }
    }
    return flag;
}
/**
 * @brief 获得伪随机数r,每次运行的随机数排列一样,可以通过srand(time(NULL))解决,但是声明要放在循环外部
 *
 * @return double
 */
static double getRandomR()
{
    
    
    return rand() / (RAND_MAX + 1.0);
}
/**
 * @brief 得到第i个变量(一共需要k次循环得到全部k个初始点)
 *
 * @param i
 * @return double
 */
static double getInitRandomX(int i)
{
    
    
    return a[i] + getRandomR() * (b[i] - a[i]);
}
/**
 * @brief 自动计算所有初始点中符合要求的点的形心xi并存入xi[N]中
 *
 * @param Struct
 * @param k
 */
static void getXi(struct initStruct *Struct, int k)
{
    
    
    int q = 0;
    memset(xi, 0, sizeof(xi));
    for (int i = 0; i < k; i++)
    {
    
    
        if (isInRange(Struct[i].x))
        {
    
    
            for (int m = 0; m < N; m++)
            {
    
    
                xi[m] += Struct[i].x[m];
            }
        }
        q++;
    }
    for (int n = 0; n < N; n++)
    {
    
    
        xi[n] = xi[n] / q;
    }
    if (q != k)
    {
    
    
        printf("本轮更新共有%d个变量在可行域内\n", q);
    }
    else
    {
    
    
        printf("复合形的形心xi为:\n");
        for (int i = 0; i < N; i++)
        {
    
    
            printf("xi[%d] = %f\n", i, xi[i]);
        }
    }
}
/**
 * @brief 得到除了最差点xh之外其他点的形心
 *
 * @param Struct
 * @param k
 */
static void getXc(struct initStruct *Struct, int k)
{
    
    
    int q = 0;
    memset(xc, 0, sizeof(xc));
    for (int i = 0; i < k - 1; i++)
    {
    
    
        if (isInRange(Struct[i].x))
        {
    
    
            for (int m = 0; m < N; m++)
            {
    
    
                xc[m] += Struct[i].x[m];
                // printf("xc[%d] = %f\n", m, xc[m]);
            }
        }
        q++;
    }
    for (int n = 0; n < N; n++)
    {
    
    
        xc[n] = xc[n] / q;
    }

    // printf("q = %d,除了最差点xh之外其他点的形心xc为: \n", q);
    // for (int i = 0; i < N; i++)
    // {
    
    
    //     printf("xc[%d] = %f\n", i, xc[i]);
    // }
}
/**
 * @brief 得到反射点xr的坐标
 *
 * @param Struct
 * @param k
 */
static void getXr()
{
    
    
    double a = alpha;
    do
    {
    
    
        for (int i = 0; i < N; i++)
        {
    
    
            xr[i] = xc[i] + a * (xc[i] - xh[i]);
        }
        a /= 2;
    } while (!(isInRange(xr)));

    printf("更新后的反射点xr为: \n");
    for (int i = 0; i < N; i++)
    {
    
    
        printf("xr[%d] = %f\n", i, xr[i]);
    }
}
/**
 * @brief 将不在可行域内的点进行更新
 *
 * @param Struct
 * @param k
 */
static void update(struct initStruct *Struct, int k)
{
    
    
    printf("复合形未能满足所有点均在可行域内,进行一次更新:\n");
    getXi(Struct, k);
    for (int i = 0; i < k; i++)
    {
    
    
        if (!(isInRange(Struct[i].x)))
        {
    
    
            for (int m = 0; m < N; m++)
            {
    
    
                Struct[i].x[m] = xi[m] + beta * (Struct[i].x[m] - xi[m]);
            }
        }
    }
}
/**
 * @brief 得到k个初始点
 *
 * @param Struct
 * @param k
 */
static void init(struct initStruct *Struct, int k)
{
    
    
    for (int i = 0; i < k; i++)
    {
    
    
        for (int j = 0; j < N; j++)
        {
    
    
            Struct[i].x[j] = getInitRandomX(j);
        }
    }
}
/**
 * @brief 将k个点对应的函数值计算出来
 *
 * @param Struct
 * @param k
 */
static void getFx(struct initStruct *Struct, int k)
{
    
    
    for (int i = 0; i < k; i++)
    {
    
    
        Struct[i].fx = f(Struct[i].x);
    }
}
/**
 * @brief 获得xl和xc中较大的值
 *
 * @param a
 * @param b
 * @return double
 */
static double max(double a, double b)
{
    
    
    return a > b ? a : b;
}
/**
 * @brief 获得xl和xc中较小的值
 *
 * @param a
 * @param b
 * @return double
 */
static double min(double a, double b)
{
    
    
    return a < b ? a : b;
}
/**
 * @brief 如果xc不在可行域内,更新边界a和b
 *
 */
static void updateXc()
{
    
    
    printf("形心xc不在可行域内,需要进行一次更新\n");
    for (int i = 0; i < N; i++)
    {
    
    
        a[i] = min(xl[i], xc[i]);
        b[i] = max(xl[i], xc[i]);
        printf("a[%d] = %f,b[%d] = %f\n", i, a[i], i, b[i]);
    }
}
/**
 * @brief 判断是否收敛
 *
 * @param Struct
 * @param k
 * @return true
 * @return false
 */
static bool isConvergence(struct initStruct *Struct, int k)
{
    
    
    double sum = 0;
    for (int i = 0; i < k; i++)
    {
    
    
        sum += pow((f(Struct->x) - f(xi)), 2);
    }

    return (pow((sum / k), 0.5) <= delta);
}
/**
 * @brief 通过判断f(xr)和f(xh)的大小关系进行迭代操作
 *
 * @param Struct
 * @param k
 */
static void updateXh(struct initStruct *Struct, int k)
{
    
    
    if (f(xr) < f(xh))
    {
    
    
        memcpy(Struct[k - 1].x, xr, sizeof(xr));
        iterate(Struct, k);
    }
    else if (f(xr) > f(xh))
    {
    
    
        double a = alpha;
        do
        {
    
    
            for (int i = 0; i < N; i++)
            {
    
    
                xr[i] = xc[i] + a * (xc[i] - xh[i]);
            }
            a /= 2;
        } while (!(isInRange(xr)) || (f(xr) > f(xh) && a > ksi));
        if (a <= ksi)
        {
    
    
            swap_arr(Struct[k - 1].x, Struct[k - 2].x);
            iterate(Struct, k);
        }
        else if (f(xr) < f(xh) && a > ksi)
        {
    
    
            memcpy(Struct[k - 1].x, xr, sizeof(xr));
            iterate(Struct, k);
        }
    }
}
/**
 * @brief 在初始化之后的迭代操作
 *
 * @param Struct
 * @param k
 */
static void iterate(struct initStruct *Struct, int k)
{
    
    
    do
    {
    
    
        getXi(Struct, k);
        getFx(Struct, k);
        qsort(Struct, EDGENUMBER, sizeof(struct initStruct), cmp);
        memcpy(xl, Struct[0].x, sizeof(xl));
        memcpy(xh, Struct[k - 1].x, sizeof(xh));
        memcpy(xg, Struct[k - 2].x, sizeof(xg));
        getXc(Struct, k);
        if (!(isInRange(xc)))
        {
    
    
            updateXc();
        }
    } while (!(isInRange(xc)));
    getXr();
}
/**
 * @brief 将两个数组交换,主要用于交换xg和xh
 *
 * @param arr_a
 * @param arr_b
 */
void swap_arr(double *arr_a, double *arr_b)
{
    
    
    double temp[N];
    memcpy(temp, b, sizeof(b));
    memcpy(b, a, sizeof(a));
    memcpy(a, temp, sizeof(a));
}
/**
 * @brief 初始化测试函数
 *
 */
void sayCS()
{
    
    
    printf("这是通过 复合形法 求解约束优化问题:\n");
}

cs.h

#ifndef CS_H
#define CS_H

#include <stdbool.h>

extern void sayCS();
extern void CS();

#endif

main.c

#include "cs.h"

void main()
{
    
    
    CS();
}

运行结果

求解:
m i n : f ( x ) = x 1 2 + x 2 2 − x 1 x 2 − 10 x 1 − 4 x 2 = 60 min:f(x) = x_1^2+x_2^2-x_1x_2-10x_1-4x_2=60 min:f(x)=x12+x22x1x210x14x2=60
约束条件:
g 1 ( x ) = x 1 ≥ 0 g 2 ( x ) = 6 − x 1 ≥ 0 g 3 ( x ) = x 2 − 1 ≥ 0 g 4 ( x ) = 8 − x 2 ≥ 0 g 5 ( x ) = 11 − x 1 − x 2 ≥ 0 g_1(x)=x_1\geq0\\ g_2(x)=6-x_1\geq0\\ g_3(x)=x_2-1\geq0\\ g_4(x)=8-x_2\geq0\\ g_5(x)=11-x_1-x_2\geq0 g1(x)=x10g2(x)=6x10g3(x)=x210g4(x)=8x20g5(x)=11x1x20
运行结果:

这是初始化后的第49次迭代:
复合形的形心xi为:
xi[0] = 5.999995
xi[1] = 4.999080
更新后的反射点xr为:
xr[0] = 5.999999
xr[1] = 4.999104
优化的最终结果为:
x[0] = 5.999997
x[1] = 4.999305
函数的最优解fx = 11.000009

经过49次迭代,达到最优结果

猜你喜欢

转载自blog.csdn.net/buaa_zhn/article/details/127538374