You are on page 1of 14

《优化计算技术》设计报告

《优化计算技术》
设计报告

设计题目 求解测试资源分配问题的
NSGA-II 约束处理技术实现

学生姓名 戴航

学 号 2020215467

专业班级 智能科技 20-1 班

授课教师 张国富、苏兆品

2022 年 9 月 27 日
《优化计算技术》设计报告

一、任务内容与要求
1. 基于所给的 NSGA2-Repair 源码和测试数据,新建工程实现 G. Zhang, Z. Su,
M. Li, F. Yue, J. Jiang and X. Yao, "Constraint Handling in NSGA-II for Solving Optimal
Testing Resource Allocation Problems," in IEEE Transactions on Reliability, vol. 66, no.
4, pp. 1193-1212, Dec. 2017, doi: 10.1109/TR.2017.2738660 中三种约束处理技术:种
群初始化、模拟二进制交叉和多项式变异。
2. 与无约束处理的NSGA2-Repair进行对比分析,基于objspace.m比较最优解集
的优劣,并分析原因。

二、具体实现
1. 带约束处理的种群初始化函数(基于论文中的Fig.3)
(1)简述原理:
原始的初始化直接对各个体的每个分量在范围内均匀随机产生。修改后算法为
了处理分量之和<=T 的约束,若分量之和>T 需要进入修复过程。核心公式如下:

(2)源码(需要用 C++14 或以上标准编译,并包含 vector 头文件):


// normal distribution with given range
double rndreal_norm(double lo, double hi) {
    static bool init = false;
    if (!init) {
        initrandomnormaldeviate();
        init = true;
    }
    // 3*sigma=hi-lo; mu=(hi+lo)/2
    double x = hi + 1;
    while (x < lo || x > hi)
        x = noise((hi + lo) / 2, (hi - lo) / 3);
    assert(lo <= x && x <= hi);
    return x;
}
void realinit(population *pop_ptr) {
    int i, j;
    double d;

    for (i = 0; i < popsize; i++) {


        double sum = 0;
        for (j = 0; j < nvar; j++) {
《优化计算技术》设计报告

            /*limits are specified it generates the value in range of


minimum
             * and maximum value of the variable*/
            pop_ptr->ind[i].xreal[j] = rndreal_norm(0, T_MAX_RESOURCE);

            sum += pop_ptr->ind[i].xreal[j];
        }
        // repair
        if (sum > T_MAX_RESOURCE) {
            for (j = 0; j < nvar; j++) {
                pop_ptr->ind[i].xreal[j] *=
                    rndreal_norm(0, 1) * (T_MAX_RESOURCE / sum);
            }
        }
    }
}

2. 带约束处理的模拟二进制交叉函数(基于论文中的Fig.5)
(1)简述原理:
原算法对分量超过限制是采用直接 clamp 的方法修复,而修改算法修复的思想
是:(1)只修复参与交叉的分量;(2)保持平均值原则;(3)保持分量进化的趋势。核
心公式如下:

此外,原算法同样没有处理分量之和的约束,与前面类似地,修改后算法需要
对非法情况进行修复。由于平均值原则被保留,这里违反分量和约束的至多只有 1
《优化计算技术》设计报告

个个体。这样,我们延续前面的思想对参与交叉的分量做修复,采用缩放因子控制
修复的程度。注意由于平均值原则,缩放因子不能太小,其下界可以通过解不等式
得到。核心公式如下:

(2)源码(需要用 C++14 或以上标准编译,并包含 vector 头文件):


void realcross(population *new_pop_ptr, population *mate_pop_ptr) {
    int i, j, y, n;
    double rnd, par1, par2, chld1, chld2, betaq, beta, alpha;
    double y1, y2, yu, yl, expp;

    vector<int> mut_idx;
    double tau1 = 0, tau2 = 0, tau1_m = 0, tau2_m = 0;

    y = 0;
    n = 0;
    for (i = 0; i < popsize / 2; i++) {
        rnd = randomperc();
        tau1 = 0, tau2 = 0, tau1_m = 0, tau2_m = 0;
        mut_idx.clear();

        /*Check Whether the cross-over to be performed*/


        if (rnd <= pcross) {
《优化计算技术》设计报告

            /*Loop over no of variables*/


            for (j = 0; j < nvar; j++) {
                /*Selected Two Parents*/
                par1 = mate_pop_ptr->ind[y].xreal[j];
                par2 = mate_pop_ptr->ind[y + 1].xreal[j];

                yl = lim_r[j][0];
                yu = lim_r[j][1];

                rnd = randomperc();

                /* Check whether variable is selected or not*/


                if (rnd <= 0.5) {
                    /*Variable selected*/
                    mut_idx.push_back(j);

                    if (fabs(par1 - par2) > EPSION) {


                        if (par2 > par1) {
                            y2 = par2;
                            y1 = par1;
                        } else {
                            y2 = par1;
                            y1 = par2;
                        }

                        /*Find beta value*/


                        if ((y1 - yl) > (yu - y2)) {
                            beta = 1 + (2 * (yu - y2) / (y2 - y1));
                            // printf("beta = %f\n",beta);
                        } else {
                            beta = 1 + (2 * (y1 - yl) / (y2 - y1));
                            // printf("beta = %f\n",beta);
                        }

                        /*Find alpha*/
                        expp = di + 1.0;

                        beta = 1.0 / beta;

                        alpha = 2.0 - pow(beta, expp);

                        if (alpha < 0.0) {


《优化计算技术》设计报告

                            printf("ERRRROR %f %d %d %f %f\n", alpha, y,


n,
                                   par1, par2);
                            exit(-1);
                        }

                        rnd = randomperc();

                        if (rnd <= 1.0 / alpha) {


                            alpha = alpha * rnd;
                            expp = 1.0 / (di + 1.0);
                            betaq = pow(alpha, expp);
                        } else {
                            alpha = alpha * rnd;
                            alpha = 1.0 / (2.0 - alpha);
                            expp = 1.0 / (di + 1.0);
                            if (alpha < 0.0) {
                                printf("ERRRORRR \n");
                                exit(-1);
                            }
                            betaq = pow(alpha, expp);
                        }

                        /*Generating two children*/


                        chld1 = 0.5 * ((y1 + y2) - betaq * (y2 - y1));
                        chld2 = 0.5 * ((y1 + y2) + betaq * (y2 - y1));

                    } else {

                        betaq = 1.0;
                        y1 = par1;
                        y2 = par2;

                        /*Generation two children*/


                        chld1 = 0.5 * ((y1 + y2) - betaq * (y2 - y1));
                        chld2 = 0.5 * ((y1 + y2) + betaq * (y2 - y1));
                    }

                    /*Repair encoding*/
                    if (chld1 < 0 || chld2 > T_MAX_RESOURCE) {
                        if (y1 <= T_MAX_RESOURCE - y2) {
                            // prefer (0,y1) interv
                            chld1 = rndreal_norm(0, y1);
                            chld2 = y1 + y2 - chld1;
《优化计算技术》设计报告

                        } else {
                            chld2 = rndreal_norm(y2, T_MAX_RESOURCE);
                            chld1 = y1 + y2 - chld2;
                        }
                    }

                    // var mutated, accumulate


                    tau1_m += chld1;
                    tau2_m += chld2;
                } else {

                    /*Copying the children to parents*/


                    chld1 = par1;
                    chld2 = par2;
                }
                new_pop_ptr->ind[n].xreal[j] = chld1;
                new_pop_ptr->ind[n + 1].xreal[j] = chld2;

                tau1 += chld1;
                tau2 += chld2;
            }
            // end for loop, all vars updated, repair constraints
            if (tau1 > T_MAX_RESOURCE) {
                double T_m = T_MAX_RESOURCE - (tau1 - tau1_m);
                double eta = max(0.0, (tau2 + tau1_m - T_MAX_RESOURCE) /
T_m);
                for (int j : mut_idx) {
                    chld1 = new_pop_ptr->ind[n].xreal[j] *
                            rndreal_norm(eta, 1) * (T_m / tau1_m);
                    chld2 = new_pop_ptr->ind[n].xreal[j] +
                            new_pop_ptr->ind[n + 1].xreal[j] - chld1;

                    new_pop_ptr->ind[n].xreal[j] = chld1;
                    new_pop_ptr->ind[n + 1].xreal[j] = chld2;
                }
            }
            if (tau2 > T_MAX_RESOURCE) {
                double T_m = T_MAX_RESOURCE - (tau2 - tau2_m);
                double eta = max(0.0, (tau1 + tau2_m - T_MAX_RESOURCE) /
T_m);
                for (int j : mut_idx) {
                    chld2 = new_pop_ptr->ind[n + 1].xreal[j] *
                            rndreal_norm(eta, 1) * (T_m / tau2_m);
                    chld1 = new_pop_ptr->ind[n].xreal[j] +
《优化计算技术》设计报告

                            new_pop_ptr->ind[n + 1].xreal[j] - chld2;

                    new_pop_ptr->ind[n].xreal[j] = chld1;
                    new_pop_ptr->ind[n + 1].xreal[j] = chld2;
                }
            }

        } else {
            // ind dont mutate, no additional repair needed
            for (j = 0; j < nvar; j++) {
                par1 = mate_pop_ptr->ind[y].xreal[j];
                par2 = mate_pop_ptr->ind[y + 1].xreal[j];
                chld1 = par1;
                chld2 = par2;
                new_pop_ptr->ind[n].xreal[j] = chld1;
                new_pop_ptr->ind[n + 1].xreal[j] = chld2;
            }
        }
        n = n + 2;
        y = y + 2;
    }
    // cerr << "cross\n";
}

3. 带约束处理的多项式变异函数(基于论文中的Fig.6)
(1)简述原理:
与交叉一致,原算法对分量超过限制是采用直接 clamp 的方法修复。而修改算
法修复的思想是:(1)只修复参与变异的分量;(2)保持分量进化的趋势。核心公式如
下:
《优化计算技术》设计报告

原算法没有处理分量之和的约束,与前面类似地,修改后算法需要对非法情况
进行修复。这里采用的是和初始化类似的修复方式,但只对变异的分量进行修复
(而不是整个个体)。核心公式如下:

(2)源码(需要用 C++14 或以上标准编译,并包含 vector 头文件):


void real_mutate(population *new_pop_ptr) {
    int i, j;

    double rnd, delta, indi, deltaq;

    double y, yl, yu, val, xy;

    double chld;

    double tau, tau_m, T_m;


    vector<int> mut_idx;

    for (j = 0; j < popsize; j++) {


        tau = 0, tau_m = 0, T_m = 0;
        mut_idx.clear();

        for (i = 0; i < nvar; i++) {


            rnd = randomperc();

            /*For each variable find whether to do mutation or not*/


《优化计算技术》设计报告

            if (rnd <= pmut_r) {


                // do mutation
                mut_idx.push_back(i);

                y = new_pop_ptr->ind[j].xreal[i];
                yl = lim_r[i][0];
                yu = lim_r[i][1];

                if (y > yl) {
                    /*Calculate delta*/

                    if ((y - yl) < (yu - y))


                        delta = (y - yl) / (yu - yl);
                    else
                        delta = (yu - y) / (yu - yl);

                    rnd = randomperc();

                    indi = 1.0 / (dim + 1.0);

                    if (rnd <= 0.5) {


                        xy = 1.0 - delta;
                        val = 2 * rnd + (1 - 2 * rnd) * (pow(xy, (dim +
1)));
                        deltaq = pow(val, indi) - 1.0;
                    } else {
                        xy = 1.0 - delta;
                        val = 2.0 * (1.0 - rnd) +
                              2.0 * (rnd - 0.5) * (pow(xy, (dim + 1)));
                        deltaq = 1.0 - (pow(val, indi));
                    }

                    /*Change the value for the parent */


                    chld = y + deltaq * (yu - yl);

                    /*Repair encoding*/
                    if (chld < lim_r[i][0]) {
                        chld = rndreal_norm(0, y);
                    }

                    if (chld > lim_r[i][1]) {


                        chld = rndreal_norm(y, T_MAX_RESOURCE);
                    }
《优化计算技术》设计报告

                    new_pop_ptr->ind[j].xreal[i] = chld;
                } else // y == yl
                {
                    xy = randomperc();
                    new_pop_ptr->ind[j].xreal[i] = xy * (yu - yl) + yl;
                }

                tau_m += new_pop_ptr->ind[j].xreal[i];
            } // end of mutation

            tau += new_pop_ptr->ind[j].xreal[i];
        } // end of i

        // repair constraints
        if (tau > T_MAX_RESOURCE) {
            T_m = T_MAX_RESOURCE - (tau - tau_m);
            for (int i : mut_idx) {
                new_pop_ptr->ind[j].xreal[i] *=
                    rndreal_norm(0, 1) * (T_m / tau_m);
            }
        }
    }
}

三、解集对比分析
1.无约束处理的NSGA2-Repair解集(matlab画图)
《优化计算技术》设计报告

2.带约束处理的NSGA2-Repair解集(matlab画图)

3.实验结果分析
对比可以看出,带有约束处理的算法得到的边界略为密集(变化在 f1=0.2 处
较明显),这说明改进算法有更好的效果。
《优化计算技术》设计报告

原始的 NSGA-II 在处理限制时只是软性地在排序时降低相应个体的优先级,


并在最后选择结果的时候丢弃非法个体。根据论文, OTRAP 问题的可行解空间很
小,因此可以猜测原始算法在进化时始终维护着一些不可行解并让它们参与种群进
化,这可能会对种群进化产生负面影响。修改后的算法保证了进化过程中所有个体
都落入可行解空间内,增加了有效个体的数量,因此可以取得更好的结果。

四、其他对比分析(可选加分项)
论文中有一处比较怪异的地方,即所有随机数都是从正态分布中得到的,但都
没有注明分布的参数(下图为一例)。在上面的代码中,正态分布的参数是以区间
中点为均值、令 3 倍标准差处与区间端点重合得到的。

这个设定的一个后果是朴素初始化算法被修改,分布从原始的均匀分布变为参
数未明的正态分布。从初始化的目的(产生足够多样性)来看,这样的修改是不太
合适的,因此这里猜测”normal distribution”实际应为”uniform distribution”。做相
应修改后,实验结果如下图。可以看到修改后结果更好,猜测这是因为初始种群带
有更多多样性的结果。
《优化计算技术》设计报告

设计报告成绩评定表

评价内容 权重 得分

代码 原理是否理解;程序能否运行;结果是否准确;任 0.5
验收 务是否全部完成。

设计 报告格式是否规范,语言使用是否规范,行文是否 0.5
报告 流畅,是否图文并茂。

合计

任课教师(签章): 年 月 日

You might also like