C# implements multi-objective particle swarm optimization algorithm (MOPSO)

C# implements multi-objective particle swarm optimization algorithm (MOPSO)

Here's how to use C# to implement the multi-objective particle swarm optimization algorithm.
This tutorial is based on MATLAB to realize the multi-objective particle swarm algorithm for C# reproduction . MATLAB has many ready-made matrix operation functions, and C# needs to be written by yourself. Therefore, the C# MOPSO source code is not very rigorous in algorithm details, and there is a lot of room for optimization and improvement. But the program runs fine.

Program source code download link:

Link: https://pan.baidu.com/s/1PudUnIm_YHaMolNdGlzPxQ
Extraction code: hzdz

Program running effect:

C# needs to rely on some external libraries, such as opengl, to realize the drawing of points in three-dimensional space, so this article directly outputs the final result in txt format and imports it into MATLAB for display.
It is consistent with the consistent results in MATLAB:
when there are two optimization objective functions, and the optimization objective function is set reasonably, ideally, the optimization result of MOPSO is linear in the plane.
When there are 3 optimization objective functions and the optimization objective function is set reasonably, ideally, the optimization result of MOPSO is planar in space, as shown in the figure below.
insert image description here
insert image description here

1. C# main program

using System;
using System.IO;

struct empty_particle
{
    
    
    public double[] Position;//记录粒子的位置
    public double[] Velocity;//记录粒子的速度向量
    public double[] Cost;//记录粒子的目标值向量
    public double[] Best_Position;//粒子最佳位置向量
    public double[] Best_Cost;//粒子最佳目标值向量
    public int IsDominated;//粒子被支配个体向量
    public int GridIndex;//粒子栅格索引向量
    public int[] GridSubIndex;//粒子栅格子索引向量
};

struct empty_Grid
{
    
    
    public double[] LB;//记录网络的经纬度
    public double[] UB;//记录网络的经纬度
};

namespace MOPSO
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            MOPSO();
        }

        //多目标粒子群优化
        static void MOPSO()
        {
    
    
            int nVar = 2;                                      //变量个数
            int[] VarSize = {
    
     1, nVar };                       //变量矩阵大小
            int VarMin = 0;                                    //变量值定义域
            int VarMax = 360;                                  //注意:该函数变量不能出现负值
            int MaxIt = 400;                                   //最大迭代次数
            int N = 40;                                        //种群规模
            int nRep = 50;                                     //档案库大小
            double w = 0.9;                                    //惯性权重系数
            double wdamp = 0.99;                               //惯性权重衰减率
            double c1 = 1.7;                                   //个体学习因子
            double c2 = 1.8;                                   //全局学习因子
            int nGrid = 5;                                     //每一维的分格数
            double alpha = 0.1;                                //膨胀率
            double beta = 2;                                   //最佳选择压
            double gamma = 2;                                  //删除选择压
            double mu = 0.1;                                   //变异概率

            empty_particle[] pop = new empty_particle[N];                // 初始粒子群
            //初始化种群中的个体的位置、速度、目标值
            for (int i = 0; i < N; i++)
            {
    
    
                //随机数
                Random rd = new Random();
                //初始化粒子的位置,即两个自变量
                pop[i].Position = new double[] {
    
     rd.Next(VarMin*100, VarMax * 100)/100.0, rd.Next(VarMin * 100, VarMax * 100)/100.0 };
                pop[i].Velocity = new double[] {
    
     0.0, 0.0 };
                pop[i].Cost = evaluate_objective(pop[i].Position);
                pop[i].Best_Position = pop[i].Position;
                pop[i].Best_Cost = pop[i].Cost;
            }
            //初始化种群中的个体的支配状况
            DetermineDomination(pop);
            //筛选出没有被支配的个体数
            empty_particle[] rep = IsNotDominated(pop);
            //创建初始网格
            empty_Grid[] Grid = CreateGrid(rep, nGrid, alpha);
            //找每个个体初始的网格位置
            FindGridIndex(rep, Grid);

            //%MOPSO主循环
            for(int it = 0;it < MaxIt; it++)
            {
    
    
                //逐一个体更新速度和位置,0.5的概率发生变异
                for (int i = 0; i<N; i++)
                {
    
    
                    //从支配个体轮盘赌选出全局最佳个体
                    empty_particle leader = SelectLeader(rep, beta);
                    empty_particle[] Temp_rep = IsNotDominated(pop);
                    empty_particle[] new_rep = new empty_particle[rep.Length+ Temp_rep.Length];
                    rep.CopyTo(new_rep, 0);
                    Temp_rep.CopyTo(new_rep, rep.Length);
                    rep = new_rep;
                    Temp_rep = null;
                    new_rep = null;
                    Random rd = new Random();
                    double r1 = (rd.Next(0, 10000)) / 10000.0;
                    double r2 = (rd.Next(0, 10000)) / 10000.0;
                    // 速度更新
                    for (int j = 0;j< pop[i].Velocity.Length;j++)
                    {
    
    
                        pop[i].Velocity[j] = w * pop[i].Velocity[j] + c1 * r1 * (pop[i].Best_Position[j] - pop[i].Position[j]) + c2*r2* (leader.Position[j] - pop[i].Position[j]);
                    }
                    //位置更新
                    for (int j = 0; j < pop[i].Position.Length; j++)
                    {
    
    
                        pop[i].Position[j] = pop[i].Position[j] + pop[i].Velocity[j];
                    }
                    //限制变量变化范围
                    pop[i].Position = limitToPosition(pop[i].Position, VarMin, VarMax);
                    //计算目标函数值
                    pop[i].Cost = evaluate_objective(pop[i].Position);
                    //应用变异策略
                    double pm = (1 - (it - 0) / Math.Pow((MaxIt - 0),(1 / mu))); //变异概率逐渐变小
                    
                    empty_particle NewSol;
                    NewSol.Position = Mutate(pop[i].Position, pm, VarMin, VarMax);
                    NewSol.Cost = evaluate_objective(NewSol.Position);   // 计算变异后的目标值
                    if(Dominates(NewSol.Cost, pop[i].Cost))
                    {
    
    
                        pop[i].Position = NewSol.Position;
                        pop[i].Cost = NewSol.Cost;
                    }
                    else
                    {
    
    
                        double rand = (rd.Next(0, 10000)) / 10000.0;
                        if(rand < 0.5)
                        {
    
    
                            pop[i].Position = NewSol.Position;
                            pop[i].Cost = NewSol.Cost;
                        }
                    }
                    //% 如果当前个体优于先前最佳个体,则替换之
                    if(Dominates(pop[i].Cost, pop[i].Best_Cost))
                    {
    
    
                        pop[i].Best_Position = pop[i].Position;
                        pop[i].Best_Cost = pop[i].Cost;
                    }
                    else
                    {
    
    
                        double rand = (rd.Next(0, 10000)) / 10000.0;
                        if (rand < 0.5)
                        {
    
    
                            pop[i].Best_Position = pop[i].Position;
                            pop[i].Best_Cost = pop[i].Cost;
                        }
                    }
                    //Console.WriteLine(i);
                }

                DetermineDomination(rep);
                //筛选出没有被支配的个体数
                empty_particle[] T_rep = IsNotDominated(rep);
                rep = T_rep;
                Grid = CreateGrid(rep, nGrid, alpha);
                //找每个个体初始的网格位置
                FindGridIndex(rep, Grid);
                if(rep.Length>nRep)
                {
    
    
                    int Extra = rep.Length - nRep;
                    for(int e=0;e < Extra;e++)
                    {
    
    
                        rep = DeleteOneRepMemebr(rep, gamma);
                    }    
                }

                Console.Write("迭代次数 =");
                Console.WriteLine(it);
                w = w * wdamp;
            }
            Console.WriteLine("迭代完成!!");
            pc2TXT(rep);
        }

        //计算目标函数值 
        static double[] evaluate_objective(double[] x)
        {
    
    
            double f1 = x[0] * 0.01;
            double f2 = (361 - x[0]) * (361 - x[1]) * 0.02;
            double f3 = x[1] * 0.01;
            double[] f = new double[] {
    
     f1, f2, f3 };
            return f;
        }

        //判断全局支配状况,返回0 = 非支配解 
        static void DetermineDomination(empty_particle[] pop)
        {
    
    
            int nPop = pop.Length;
            for(int i = 0;i<nPop;i++)
            {
    
    
                pop[i].IsDominated = 0;//初始化为互不支配 
            }
            for(int i = 0;i< nPop - 1; i++)
            {
    
    
                for(int j = i+1;j< nPop;j++)
                {
    
    
                    if(Dominates(pop[i].Cost, pop[j].Cost))
                    {
    
    
                        pop[j].IsDominated = 1;
                    }
                    if(Dominates(pop[j].Cost, pop[i].Cost))
                    {
    
    
                        pop[i].IsDominated = 1;
                    }
                }
            }
        }

        //%判断两个目标值x,y的支配状态 
        //x支配y,返回1;y支配x,返回0
        static bool Dominates(double[] x,double[] y)
        {
    
    
            int flag_all = 1;
            int flag_any = 0;
            //x对应的每一位上的数要小于等于y
            for (int i = 0;i<x.Length;i++)
            {
    
    
                if(x[i] > y[i])
                {
    
    
                    flag_all = 0;
                    break;
                }   
            }
            //x对应的每一位上的数一定要比y中的某一位要小
            for (int i = 0; i < x.Length; i++)
            {
    
    
                for (int j = 0; j < y.Length; j++)
                {
    
    
                    if (x[i] < y[j])
                    {
    
    
                        flag_any++;
                        break;
                    }
                }
            }

            if(flag_all == 1 && flag_any == x.Length)
            {
    
    
                return true;
            }
            else
            {
    
    
                return false;
            }
        }
        //判断没有被支配的个体数
        static empty_particle[] IsNotDominated(empty_particle[] pop)
        {
    
    
            int nPop = pop.Length;
            int num = 0;
            for (int i = 0; i < nPop; i++)
            {
    
    
                if (pop[i].IsDominated == 0)
                    num++;
            }
            empty_particle[] rep = new empty_particle[num];
            int j=0;
            for (int i = 0; i < nPop; i++)
            {
    
    
                if (pop[i].IsDominated == 0)
                {
    
    
                    empty_particle temp = new empty_particle();
                    double temp_double;
                    int temp_int;
                    temp.Position = new double[pop[i].Position.Length];
                    for (int k=0;k<pop[i].Position.Length;k++)
                    {
    
    
                        temp_double = pop[i].Position[k];
                        temp.Position[k] = temp_double;
                    }
                    temp.Cost = new double[pop[i].Cost.Length];
                    for (int k = 0; k < pop[i].Cost.Length; k++)
                    {
    
    
                        temp_double = pop[i].Cost[k];
                        temp.Cost[k] = temp_double;
                    }
                    temp.Velocity = new double[pop[i].Velocity.Length];
                    for (int k = 0; k < pop[i].Velocity.Length; k++)
                    {
    
    
                        temp_double = pop[i].Velocity[k];
                        temp.Velocity[k] = temp_double;
                    }
                    temp.Best_Cost = new double[pop[i].Best_Cost.Length];
                    for (int k = 0; k < pop[i].Best_Cost.Length; k++)
                    {
    
    
                        temp_double = pop[i].Best_Cost[k];
                        temp.Best_Cost[k] = temp_double;
                    }
                    temp.Best_Position = new double[pop[i].Best_Position.Length];
                    for (int k = 0; k < pop[i].Best_Position.Length; k++)
                    {
    
    
                        temp_double = pop[i].Best_Position[k];
                        temp.Best_Position[k] = temp_double;
                    }
                    //temp.GridSubIndex = new int[pop[i].GridSubIndex.Length];
                    //for (int k = 0; k < pop[i].GridSubIndex.Length; k++)
                    //{
    
    
                    //    temp_int = pop[i].GridSubIndex[k];
                    //    temp.GridSubIndex[k] = temp_int;
                    //}
                    temp_int = pop[i].IsDominated;
                    temp.IsDominated = temp_int;
                    temp_int = pop[i].GridIndex;
                    temp.GridIndex = temp_int;

                    rep[j] = temp;
                    j++;
                }
            }

            return rep;
        }

        //创建网格
        static empty_Grid[] CreateGrid(empty_particle[] pop, int nGrid,double alpha)
        {
    
    
            int nPop = pop.Length;
            int N = pop[0].Cost.Length;
            //找出每个个体中Cost每一位上的最大最小值
            double[] cmin = new double[3] {
    
     pop[0].Cost[0], pop[0].Cost[1], pop[0].Cost[2] };
            double[] cmax = new double[3] {
    
     pop[0].Cost[0], pop[0].Cost[1], pop[0].Cost[2] };
            for (int i = 0; i < nPop; i++)
            {
    
    
                for(int j = 0;j<3;j++)
                {
    
    
                    if(pop[i].Cost[j]< cmin[j])
                    {
    
    
                        cmin[j] = pop[i].Cost[j];
                    }
                    if(pop[i].Cost[j] > cmax[j])
                    {
    
    
                        cmax[j] = pop[i].Cost[j];
                    }
                }
            }
            double[] dc = new double[3] {
    
     cmax[0] - cmin[0], cmax[1] - cmin[1], cmax[2] - cmin[2] };
            //扩大10%
            for(int i=0;i<3;i++)
            {
    
    
                cmin[i] = cmin[i] - alpha * dc[i];
                cmax[i] = cmax[i] + alpha * dc[i];
            }
            int nObj = cmin.Length;
            //创建网格
            empty_Grid[] Grid = new empty_Grid[3];
            //大数
            double big = 100000;
            for(int i=0;i<nObj;i++)
            {
    
    
                double interval = (cmax[i] - cmin[i]) / nGrid;
                Grid[i].LB = new double[nGrid+2];
                Grid[i].LB[0] = -big;
                for(int j =1;j< Grid[i].LB.Length;j++)
                {
    
    
                    Grid[i].LB[j] = cmin[i] + interval * (j - 1);
                }
                Grid[i].UB = new double[nGrid + 2];
                Grid[i].UB[Grid[i].LB.Length-1] = big;
                for (int j = 0; j < Grid[i].LB.Length-1; j++)
                {
    
    
                    Grid[i].UB[j] = cmin[i] + interval * j;
                }
            }         
            return Grid;
        }

        //判断所在的网格
        static void FindGridIndex(empty_particle[] rep, empty_Grid[] Grid)
        {
    
    
            int nObj = rep[0].Cost.Length;
            int nGrid = Grid[0].LB.Length;
            for (int i = 0; i < rep.Length; i++)
            {
    
    
                rep[i].GridSubIndex = new int[nGrid];
                for(int j=0;j<nObj;j++)
                {
    
    
                    for(int k=0;k< nGrid;k++)
                    {
    
    
                        if(rep[i].Cost[j]<=Grid[j].UB[k])
                        {
    
    
                            rep[i].GridSubIndex[j] = k;
                            break;
                        }
                    }
                }

                rep[i].GridIndex = rep[i].GridSubIndex[0];
                for(int j=1;j<nObj;j++)
                {
    
    
                    rep[i].GridIndex = rep[i].GridIndex - 1;
                    rep[i].GridIndex = nGrid * rep[i].GridIndex;
                    rep[i].GridIndex = rep[i].GridIndex + rep[i].GridSubIndex[j];
                }
            }
            
        }

        //从全局支配个体中找出一个最佳个体 
        static empty_particle SelectLeader(empty_particle[] rep,double beta)
        {
    
    
            //获取所有个体的网格序号
            int[] GI = new int[rep.Length];
            for(int i=0;i< rep.Length;i++)
            {
    
    
                GI[i] = rep[i].GridIndex;
            }
            //对网格序号进行排序
            int[] T_OC = GI;
            Array.Sort(T_OC);
            int T_length = 1;
            //去除掉所有相同的序号
            for (int i = 0; i < T_OC.Length - 1; i++)
            {
    
    
                if(T_OC[i]!=T_OC[i+1])
                {
    
    
                    T_length++;
                }
            }
            int[] OC = new int[T_length];
            OC[0] = T_OC[0];
            int T_i = 1;
            for (int i = 0; i < T_OC.Length - 1; i++)
            {
    
    
                if (T_OC[i] != T_OC[i + 1])
                {
    
    
                    OC[T_i] = T_OC[i+1];
                    T_i++;
                }
            }
            //对相同的序号进行计数
            int[] N = new int[T_length];
            for (int i = 0; i < OC.Length; i++)
            {
    
    
                for(int j=0;j < T_OC.Length;j++)
                {
    
    
                    if (OC[i] == T_OC[j])
                    {
    
    
                        N[i]++;
                    }
                }
            }
            // 计算选择概率,为了增加多样性,尽量不选多次出现的个体
            // 如果N大P就小, 即多次出现的栅格点被选中的概率小
            double[] P = new double[T_length];
            double T_sum = 0;
            for (int i = 0; i < T_length; i++)
            {
    
    
                P[i] = Math.Pow(Math.E, -beta * N[i]);
                T_sum = T_sum + P[i];
            }
            for (int i = 0; i < T_length; i++)
            {
    
    
                P[i] = P[i]/T_sum;
            }
            //轮盘赌策略选择
            int sci = RouletteWheelSelection(P);
            int sc = OC[sci];   //轮盘赌选择的栅格点
            int T_SCM_Length = 0;
            
            for (int i = 0; i < rep.Length; i++)
            {
    
    
                GI[i] = rep[i].GridIndex;
            }

            for (int i = 0; i < GI.Length; i++)
            {
    
    
                if (GI[i] == sc)
                {
    
    
                    T_SCM_Length++;
                }
            }

            int[] SCM = new int[T_SCM_Length];
            int T_SCM_i = 0;
            for(int i = 0; i < GI.Length; i++)
            {
    
    
                if (GI[i] == sc)
                {
    
    
                    SCM[T_SCM_i] = i;
                    T_SCM_i++;
                }
            }
            Random rd = new Random();
            int smi = rd.Next(0, T_SCM_Length);
            int sm = SCM[smi];

            //当前全局最佳位置点
            return rep[sm];
        }

        //%轮盘赌选择一个较好的支配个体
        static int RouletteWheelSelection(double[] P)
        {
    
    
            //随机数
            Random rd = new Random();
            double r = (rd.Next(0,10000))/10000.0;
            double sum = 0;
            int i;
            for(i=0;i<P.Length;i++)
            {
    
    
                sum = sum + P[i];
                if(sum>r)
                {
    
    
                    break;
                }
            }
            if (i >= P.Length)
                i = P.Length - 1;
            return i;

        }

        //位置限制
        static double[] limitToPosition(double[] Position, int VarMin,int VarMax)
        {
    
    
            for(int i =0;i< Position.Length;i++)
            {
    
    
                if (Position[i]< VarMin)
                {
    
    
                    Position[i] = VarMin;
                }
                if(Position[i] > VarMax)
                {
    
    
                    Position[i] = VarMax;
                }
            }
            return Position;
        }

        //使用变异策略
        static double[] Mutate(double[] x,double pm,int VarMin,int VarMax)
        {
    
    
            int nVar = x.Length;
            Random rd = new Random();
            int j = rd.Next(0,nVar - 1);
            double dx = pm * (VarMax - VarMin);
            double lb = x[j] - dx;
            if(lb < VarMin)
            {
    
    
                lb = VarMin;
            }
            double ub = x[j] + dx;
            if(ub > VarMax)
            {
    
    
                ub = VarMax;
            }
            double[] xnew = new double[x.Length];
            for(int i=0;i< x.Length;i++)
            {
    
    
                double temp = x[i];
                xnew[i] = temp;
            }
            xnew[j] = rd.Next((int)lb, (int)ub);
            return xnew;
        }
        //删除档案库中的一个个体
        static empty_particle[] DeleteOneRepMemebr(empty_particle[] rep, double gamma)
        {
    
    
            int[] GI = new int[rep.Length];
            for(int i=0;i< rep.Length;i++)
            {
    
    
                GI[i] = rep[i].GridIndex;
            }

            //对网格序号进行排序
            int[] T_OC = GI;
            Array.Sort(T_OC);
            int T_length = 1;
            //去除掉所有相同的序号
            for (int i = 0; i < T_OC.Length - 1; i++)
            {
    
    
                if (T_OC[i] != T_OC[i + 1])
                {
    
    
                    T_length++;
                }
            }
            int[] OC = new int[T_length];
            OC[0] = T_OC[0];
            int T_i = 1;
            for (int i = 0; i < T_OC.Length - 1; i++)
            {
    
    
                if (T_OC[i] != T_OC[i + 1])
                {
    
    
                    OC[T_i] = T_OC[i + 1];
                    T_i++;
                }
            }
            //对相同的序号进行计数
            int[] N = new int[T_length];
            for (int i = 0; i < OC.Length; i++)
            {
    
    
                for (int j = 0; j < T_OC.Length; j++)
                {
    
    
                    if (OC[i] == T_OC[j])
                    {
    
    
                        N[i]++;
                    }
                }
            }
            // 计算选择概率,为了增加多样性,尽量不选多次出现的个体
            // 如果N大P就小, 即多次出现的栅格点被选中的概率小
            double[] P = new double[T_length];
            double T_sum = 0;
            for (int i = 0; i < T_length; i++)
            {
    
    
                P[i] = Math.Pow(Math.E,gamma * N[i]);
                T_sum = T_sum + P[i];
            }
            for (int i = 0; i < T_length; i++)
            {
    
    
                P[i] = P[i] / T_sum;
            }
            //轮盘赌策略选择
            int sci = RouletteWheelSelection(P);
            int sc = OC[sci];   //轮盘赌选择的栅格点
            int T_SCM_Length = 0;

            for (int i = 0; i < rep.Length; i++)
            {
    
    
                GI[i] = rep[i].GridIndex;
            }

            for (int i = 0; i < GI.Length; i++)
            {
    
    
                if (GI[i] == sc)
                {
    
    
                    T_SCM_Length++;
                }
            }

            int[] SCM = new int[T_SCM_Length];
            int T_SCM_i = 0;
            for (int i = 0; i < GI.Length; i++)
            {
    
    
                if (GI[i] == sc)
                {
    
    
                    SCM[T_SCM_i] = i;
                    T_SCM_i++;
                }
            }
            Random rd = new Random();
            int smi = rd.Next(0, T_SCM_Length);
            int sm = SCM[smi];
            empty_particle[] TT_rep = new empty_particle[rep.Length - 1];
            for (int i = 0; i < sm; i++)
            {
    
    
                TT_rep[i] = rep[i];
            }
            for (int i = sm; i < TT_rep.Length; i++)
            {
    
    
                TT_rep[i] = rep[i + 1];
            }

            return TT_rep;
        }
        //将点云保存到txt
        static void pc2TXT(empty_particle[] rep)
        {
    
    
            FileStream fs = new FileStream("D:\\12其他\\大师姐\\多目标优化\\C#\\MOPSO\\PC.txt", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            //开始写入
            foreach (var item in rep)
            {
    
    
                sw.WriteLine(item.Cost[0] + "\t" + item.Cost[1] + "\t" + item.Cost[2]);
                //清空缓冲区
                sw.Flush();
            }
            //关闭流
            sw.Close();
            fs.Close();
        }

    }
}

2. Output the result to the corresponding txt file

Change the file save path to your own path, and call it after the main program finishes running.

//将点云保存到txt
static void pc2TXT(empty_particle[] rep)
{
    
    
    FileStream fs = new FileStream("D:\\12其他\\大师姐\\多目标优化\\C#\\MOPSO\\PC.txt", FileMode.Create);
    StreamWriter sw = new StreamWriter(fs);
    //开始写入
    foreach (var item in rep)
    {
    
    
        sw.WriteLine(item.Cost[0] + "\t" + item.Cost[1] + "\t" + item.Cost[2]);
        //清空缓冲区
        sw.Flush();
    }
    //关闭流
    sw.Close();
    fs.Close();
}

3. Display program running results in MATLAB (MATLAB code)

clc;
clear;

a = textread('PC.txt');%修改成自己的txt

figure(1); 
location = a';   %取最优结果
scatter3(location(1,:),location(2,:),location(3,:),'filled','b'); 
xlabel('f1');ylabel('f2'); zlabel('f3');
title('Pareto 最优边界图'); 
box on; 

4, attention! ! !

If the result of C# running is inconsistent with the result of MATLAB.

Possible reason 1: It is very likely that the random function in C# is not random, because the random value in C# is determined by time, so there is a probability that a large number of the same random number will appear in the loop.
Solution: (1) Add some useless output at the appropriate position of the loop to reduce the speed of the loop. (Not useful for some machines); (2) Take Random rd = new Random() out of the loop, and set rd as a global variable.

Possible reason 2: The gamma value is set too large, exceeding the definition of double.
Solution: Decrease the gamma value appropriately.

Possible reason 3: When C# transfers values ​​in an array, unlike MATLAB, which only transfers values, it directly transfers addresses, resulting in that when an array is adjusted, another array is also modified.
Solution: Check whether there are similar problems in each place where the value of the array is passed, and modify it.

Guess you like

Origin blog.csdn.net/qq_42232522/article/details/124378113