种群优化算法-入侵杂草优化

入侵杂草算法的灵感来自自然界中杂草的生长过程。 这种方法是由 Mehrabian 和 Lucas 在 2006 年引入的。 很自然地,杂草生长越旺盛,这种强壮的生长对有用的植物构成了严重威胁。 杂草的一个重要特征是其抗性,和在自然界中的高适应性,这是 IWO 优化算法的基础。 该算法可作为高效优化方法的基础。

IWO 是一种连续随机数值算法,模仿杂草的定植行为。 首先,初始种子种群随机分布在整个搜索空间当中。 这些杂草最终会生长,并执行算法的进一个步骤。 该算法由七个步骤组成,可以用伪代码表示为:

1. 随机播种
2. 计算 FF
3. 来自杂草的播种
4. 计算 FF
5. 将子杂草与亲本杂草合并
6. 所有杂草进行分类
7. 重复步骤 3。 直到满足停止条件

框图表示算法在一次迭代中的操作。 IWO 从种子初始化过程开始操作。 种子随机均匀地散布在搜索空间的“领域”上。 之后,我们假设种子发芽,并已长为成年植株,这应该通过适应度函数进行评估。

下一步,了解每种植株的适应性,我们可以让杂草通过种子繁衍,其中种子的数量与适应性成正比。 之后,我们将发芽的种子与亲本植株相结合,并对其进行分类。 通常来讲,入侵性杂草算法可考虑易于编码、修改,并与第三方应用程序结合使用。

图例 1. IWO 算法框图

我们继续研究杂草算法的特性。 它具有杂草的许多极端生存适应性。 与遗传、蜜蜂和其它一些算法相对比,杂草菌落的一个显著特征是保证菌落的所有植株无一例外地得到播种。 即使是适应性最差的植株,这样一来也可以留下后代,因为最差的植株趋向全局极端的概率也始终是非零的。

正如我已经说过的,每种杂草都会在从最小可能到最大可能的数量(算法的外部参数)的范围内产生种子。 自然而然地,在这种情况下,当每棵植株至少留下一颗或多颗种子时,子植株将比亲本植株更多 — 这个特性在代码中得到了有趣的实现,将在下面讨论。 图例 2 直观显示了该算法。 亲本植株根据其适应性成比例地散布种子。

故此,1 号最好的植株播下了 6 颗种子,而 6 号的植株只播下了一粒种子(保底的种子)。 发芽的种子产生新植株,随后与亲本一起分类。 这是对生存的模仿。 从整个排序组中,选择新的亲本植株,并在下一次迭代中重复生命周期。 该算法具有的机制,能解决“人口过剩”,以及散播能力实施不彻底等问题。

例如,我们取种子数,其中一个算法参数是 50,亲本植株的数量是 5,最小种子数是 1,而最大种子数是 6。 在本例中,5 * 6 = 30,小于 50。 从这个例子中我们可以看到,播种的可能性并没有完全实施。 在这种情况下,保留后代的权利将传递到链表中的下一代,直到所有亲本植株达到允许的最大后代数量。 当到达链表末尾时,权利转到链表中的第一个,且允许留下超过限量的后代。 

图例 2. IWO 算法操作。 后代的数量与亲本的适应度成正比

接下来要注意的是种子散播。 算法中的种子散播是与迭代次数成比例的线性递减函数。 外部散播参数是种子散播的下限和上限。 因此,随着迭代次数的增加,播种半径减小,发现的极值得到细化。 根据算法作者的建议,应该采用正态散播分布,但我简化了计算,并应用了立方函数。 迭代次数的离散函数如图例 3 所示。

图例 3. 离散对迭代次数的依赖性,其中 3 是最大极限,2 是最小极限

我们继续讨论 IWO 代码。 代码执行简单快捷。

该算法最简单的单元(代理者)是“杂草”。 它还将描述杂草的种子。 这可令我们取用相同类型的数据进行后续排序。 该结构由一个坐标数组、一个存储适应度函数值的变量、和一个种子(后代)数量的计数器组成。 该计数器将令我们能够控制每种植株的最小和最大允许种子数量。

//——————————————————————————————————————————————————————————————————————————————
struct S_Weed
{
  double c []; //coordinates
  double f;    //fitness
  int    s;    //number of seeds
};
//——————————————————————————————————————————————————————————————————————————————

我们需要一个结构来实现选择亲本的概率函数,即与它们的健康状况成比例。 在这种情况下,可以应用轮盘赌原理,我们已在蜂群算法中看到了这一点。 'start' 和 'end' 变量负责概率域的开始和结束。

//——————————————————————————————————————————————————————————————————————————————
struct S_WeedFitness
{
  double start;
  double end;
};
//——————————————————————————————————————————————————————————————————————————————

我们来声明杂草算法类。 在其中,声明我们需要的所有必要变量 — 需优化参数的边界和步长,描述杂草的数组,以及种子数组,最佳全局坐标数组,和算法实现的适应度函数的最佳值。 我们还需要第一次迭代的 “sowing” 标志,和算法参数的常量变量。

//——————————————————————————————————————————————————————————————————————————————
class C_AO_IWO
{
  //============================================================================
  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search
  public: S_Weed weeds     []; //weeds
  public: S_Weed weedsT    []; //temp weeds
  public: S_Weed seeds     []; //seeds
  public: double cB        []; //best coordinates
  public: double fB;           //fitness of the best coordinates

  public: void Init (const int    coordinatesP,      //Number of coordinates
                     const int    numberSeedsP,      //Number of seeds
                     const int    numberWeedsP,      //Number of weeds
                     const int    maxNumberSeedsP,   //Maximum number of seeds per weed
                     const int    minNumberSeedsP,   //Minimum number of seeds per weed
                     const double maxDispersionP,    //Maximum dispersion
                     const double minDispersionP,    //Minimum dispersion
                     const int    maxIterationP);    //Maximum iterations

  public: void Sowing      (int iter);
  public: void Germination ();

  //============================================================================
  private: void   Sorting        ();
  private: double SeInDiSp       (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI      (double Min, double Max);
  private: double Scale          (double In, double InMIN, double InMAX, double OutMIN, double OutMAX,  bool Revers);

  private: double vec [];            //Vector
  private: int    ind [];
  private: double val [];
  private: S_WeedFitness wf [];      //Weed fitness
  private: bool   sowing;            //Sowing
  private: int    coordinates;       //Coordinates number
  private: int    numberSeeds;       //Number of seeds
  private: int    numberWeeds;       //Number of weeds
  private: int    totalNumWeeds;     //Total number of weeds
  private: int    maxNumberSeeds;    //Maximum number of seeds
  private: int    minNumberSeeds;    //Minimum number of seeds
  private: double maxDispersion;     //Maximum dispersion
  private: double minDispersion;     //Minimum dispersion
  private: int    maxIteration;      //Maximum iterations
};
//——————————————————————————————————————————————————————————————————————————————

在初始化函数的 open 方法中,为常量变量赋值,检查算法的输入参数是否都为有效值,因此亲本植株的最小可能值的乘积不能超过种子总数。 需要亲本植株和种子的总和来判定要执行排序的数组。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_IWO::Init (const int    coordinatesP,      //Number of coordinates
                     const int    numberSeedsP,      //Number of seeds
                     const int    numberWeedsP,      //Number of weeds
                     const int    maxNumberSeedsP,   //Maximum number of seeds per weed
                     const int    minNumberSeedsP,   //Minimum number of seeds per weed
                     const double maxDispersionP,    //Maximum dispersion
                     const double minDispersionP,    //Minimum dispersion
                     const int    maxIterationP)     //Maximum iterations
{
  MathSrand (GetTickCount ());
  sowing = false;
  fB     = -DBL_MAX;

  coordinates    = coordinatesP;
  numberSeeds    = numberSeedsP;
  numberWeeds    = numberWeedsP;
  maxNumberSeeds = maxNumberSeedsP;
  minNumberSeeds = minNumberSeedsP;
  maxDispersion  = maxDispersionP;
  minDispersion  = minDispersionP;
  maxIteration   = maxIterationP;


  if (minNumberSeeds < 1) minNumberSeeds = 1;
  if (numberWeeds * minNumberSeeds > numberSeeds) numberWeeds = numberSeeds / minNumberSeeds;
  else numberWeeds = numberWeedsP;

  totalNumWeeds  = numberWeeds + numberSeeds;

  ArrayResize (rangeMax,  coordinates);
  ArrayResize (rangeMin,  coordinates);
  ArrayResize (rangeStep, coordinates);
  ArrayResize (vec,       coordinates);
  ArrayResize (cB,        coordinates);

  ArrayResize (weeds,  totalNumWeeds);
  ArrayResize (weedsT, totalNumWeeds);
  ArrayResize (seeds,  numberSeeds);

  for (int i = 0; i < numberWeeds; i++)
  {
    ArrayResize (weeds  [i].c, coordinates);
    ArrayResize (weedsT [i].c, coordinates);
    weeds [i].f = -DBL_MAX;
    weeds [i].s = 0;
  }
  for (int i = 0; i < numberSeeds; i++)
  {
    ArrayResize (seeds [i].c, coordinates);
    seeds [i].s = 0;
  }

  ArrayResize (ind, totalNumWeeds);
  ArrayResize (val, totalNumWeeds);

  ArrayResize (wf, numberWeeds);
}
//——————————————————————————————————————————————————————————————————————————————

在 Sowing () 每次迭代中调用的第一个公开方法。 它包含算法的主要逻辑。 为了便于理解,我将该方法划分为几个部分。

当算法处于第一次迭代时,有必要在整个搜索空间中播下种子。 这通常是随机和均匀地完成的。 在优化参数的可接受数值范围内生成随机数后,检查获得的数值是否超出范围,并设置算法参数定义的离散性。 在此,我们还将分配一个分布向量,在代码后面播种时将需要它。 将种子适应度值初始化为最小双精度值,并重置种子计数器(将成为植株的种子会用到种子计数器)。

//the first sowing of seeds---------------------------------------------------
if (!sowing)
{
  fB = -DBL_MAX;

  for (int s = 0; s < numberSeeds; s++)
  {
    for (int c = 0; c < coordinates; c++)
    {
      seeds [s].c [c] = RNDfromCI (rangeMin [c], rangeMax [c]);
      seeds [s].c [c] = SeInDiSp (seeds [s].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);

      vec [c] = rangeMax [c] - rangeMin [c];
    }

    seeds [s].f = -DBL_MAX;
    seeds [s].s = 0;
  }

  sowing = true;
  return;
}

在这段代码中,散播是根据当前迭代计算的。 我前面提到的每种亲本杂草的保底最小种子数在这里实现。 保底的最小种子数量将由两个循环提供,在第一个循环中,我们将整理亲本植株;在第二个循环中,我们将实际生成新种子,同时增加种子计数器。 如您所见,创建新后代的意义是利用立方函数的分布递增一个随机数,并将先前计算的离散度加入到亲本坐标。 检查新坐标的获取值,以便获取可接受的数值,并分配离散性。

//guaranteed sowing of seeds by each weed-------------------------------------
int    pos = 0;
double r   = 0.0;
double dispersion = ((maxIteration - iter) / (double)maxIteration) * (maxDispersion - minDispersion) + minDispersion;

for (int w = 0; w < numberWeeds; w++)
{
  weeds [w].s = 0;

  for (int s = 0; s < minNumberSeeds; s++)
  {
    for (int c = 0; c < coordinates; c++)
    {
      r = RNDfromCI (-1.0, 1.0);
      r = r * r * r;

      seeds [pos].c [c] = weeds [w].c [c] + r * vec [c] * dispersion;
      seeds [pos].c [c] = SeInDiSp (seeds [pos].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }

    pos++;
    weeds [w].s++;
  }
}

使用此代码,我们将根据轮盘原则为每个亲本植株提供与适应度成比例的概率域。 当这里的种子数量遵循随机定律时,上面的代码为每种植株提供了保底数量的种子;因此杂草的适应性越强,它可以留下的种子就越多,反之亦然。 植株的适应性越差,它产生的种子就越少。

//============================================================================
//sowing seeds in proportion to the fitness of weeds--------------------------

//the distribution of the probability field is proportional to the fitness of weeds
wf [0].start = weeds [0].f;
wf [0].end   = wf [0].start + (weeds [0].f - weeds [numberWeeds - 1].f);

for (int f = 1; f < numberWeeds; f++)
{
  if (f != numberWeeds - 1)
  {
    wf [f].start = wf [f - 1].end;
    wf [f].end   = wf [f].start + (weeds [f].f - weeds [numberWeeds - 1].f);
  }
  else
  {
    wf [f].start = wf [f - 1].end;
    wf [f].end   = wf [f].start + (weeds [f - 1].f - weeds [f].f) * 0.1;
  }
}

根据获得的概率域,我们选择有权利留下后代的亲本植株。 如果种子计数器已达到允许的最大值,则权利传递到排序链表中的下一个计数器。 如果到达链表的末尾,则权力不会传递到下一个,而是传递到链表中的第一个。 然后根据上述规则依据计算出的散播形成子植株。

bool seedingLimit = false;
int  weedsPos = 0;

for (int s = pos; s < numberSeeds; s++)
{
  r = RNDfromCI (wf [0].start, wf [numberWeeds - 1].end);

  for (int f = 0; f < numberWeeds; f++)
  {
    if (wf [f].start <= r && r < wf [f].end)
    {       
      weedsPos = f;
      break;
    }
  }

  if (weeds [weedsPos].s >= maxNumberSeeds)
  {
    seedingLimit = false;
    while (!seedingLimit)
    {
      weedsPos++;
      if (weedsPos >= numberWeeds)
      {
        weedsPos = 0;
        seedingLimit = true;
      }
      else
      {
        if (weeds [weedsPos].s < maxNumberSeeds)
        {
          seedingLimit = true;
        }
      }
    }
  }

  for (int c = 0; c < coordinates; c++)
  {
    r = RNDfromCI (-1.0, 1.0);
    r = r * r * r;

    seeds [s].c [c] = weeds [weedsPos].c [c] + r * vec [c] * dispersion;
    seeds [s].c [c] = SeInDiSp (seeds [s].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
  }

  seeds [s].s = 0;
  weeds [weedsPos].s++;
}

第二个 open 方法是每次迭代时执行的必需方法,并且在计算每个子杂草的适应度函数后是必需的。 在应用排序之前,将发芽的种子放在公开数组之中,亲本植株位于链表的末尾,从而替换上一代,其中可能包括上一次迭代的后代和亲本。 如此,我们销毁适应性较弱的杂草,就像自然界中发生的那样。 之后,应用排序。 结果列表中的第一种杂草如果真的更好,则值得更新全局达成的最佳解。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_IWO::Germination ()
{
  for (int s = 0; s < numberSeeds; s++)
  {
    weeds [numberWeeds + s] = seeds [s];
  }

  Sorting ();

  if (weeds [0].f > fB) fB = weeds [0].f;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值