期货量化软件:种群优化算法人工蜂群(ABC)

1. 概述

群居昆虫是高度进化的生物,可以执行许多单体昆虫无法完成的复杂任务。 沟通、筑造复杂的巢穴、环境控制、保护、和分工只是蜜蜂已进化到在社会性群居地茁壮成长的少数行为。 蜂群属于群体生物,在寻找最佳解决方案方面表现出非凡的能力。 在自然界中,它们在蜂巢附近寻找花簇来采集花蜜和花粉。 有时搜索半径可以增加到几公里。 返回的蜜蜂则是通过即兴舞蹈报告它们的发现。

乍一看,这似乎是不可能的,但它们能够通过有节奏的运动相互传递有关地理位置的信息。 取决于它们同胞间的舞蹈强度,蜂群得到有关指定地点的花朵数量和估算花蜜量的结论。 潜在的食物越丰富,舞蹈动作就越激烈。 这种不寻常的现象是在 20 世纪中叶由昆虫研究员卡尔·冯·弗里施(Karl von Frisch)发现的。

多年来,蜜蜂觅食方法仅在生物学家之间研究。 然而,在开发新的优化算法时,应用群体行为的兴趣正在增长。 在 2005 年,Dervis Karaboga 教授对研究结果产生了兴趣。 他发表了一篇科学论文,是第一个描述群体智能模型的人,主要受到蜂群舞蹈的启发。 该模型被称为人工蜂群。

2. 算法说明

人工蜂群有许多不同的实现,区别在于蜂巢中管理蜂群的原则、以及区域探索规则上有所不同。 在本文中,我将讨论我对经典算法版本的解释。

该算法的思路是基于蜂群在寻找尽可能多的获取花蜜的地方时的行为。 首先,所有的蜜蜂都朝随机的方向飞出蜂巢,充当侦察员,试图寻找有花蜜的区域。 之后,蜜蜂返回蜂巢,并以特殊的方式告诉其它个体在哪里找到了花蜜、以及发现了多少花蜜。

工蜂被发配到发现的区域。 在这个地区发现的花蜜越多,向那个方向飞的蜜蜂就越多。 侦察兵再次飞去寻找其它区域,但均在已发现区域的附近。 因此,所有的蜜蜂被分为两种:采集花蜜的工蜂,和探索新区域的侦察蜂。 花蜜采集区域具有的量值,与其花蜜量相对应。 沿穿过区域中心的线,较低等级的区域由相对于较高等级的区域进行置换。

由图示,工蜂按区域分布可以在图例 1 中可视化。

添加图片注释,不超过 140 字(可选)

图例 1. 取决于区域排名,前往该区域的蜜蜂数量

区域 1 的等级较高,它包含的花蜜最多,因此更多的蜜蜂倾向于飞往那里。 通过蜜蜂的数量,我们可以直观地判定区域 4 的等级(值)最低。 蜜蜂以特殊舞蹈的形式报告有关每个区域价值的信息。 每个蜂巢都有自己的舞姿,其中对该地区花蜜的方向和数量进行编程。

假设全局位置的极值是花蜜最多的区域,并且只有一个这样的区域。 其它地方也有花蜜,尽管数量较少。 蜜蜂生活在多维空间中,其中每个坐标代表函数的一个参数,且其需要优化。 如果我们正在寻找全局最大值,则发现的花蜜量就是此刻目标函数的值。 如果我们正在寻找全局最小值,那么将目标函数乘以 -1 就足够了。

由于花蜜采集区域具有确定的价值,因此只有等级最高的区域才有权移到(中心移位)花蜜浓度最高的地点。 较低等级的区域则移至最高浓度的中心,并检查与其它较高等级区域的交叉点。 以这样的方式,不允许蜜蜂集中在一些狭窄的小区域内,并且由工蜂提供的搜索空间服务应尽可能地高效,从而防止食物来源的枯竭。 在优化方面,这消除或最大限度地减少了陷入局部极值的情况。 在区域分散,并沿着等级链相互移动到其最优位置后,蜜蜂侦察兵将深入侦察它们的邻域。

许多养蜂人建议将侦察蜂遣派到搜索空间的随机区域,但我的经验表明,这种“侦察”的实际价值接近于零,并且只对一、两个维度有用。 换言之,如果我们谈论的是多维空间,那么自由度就会呈几何级数增加,并且很难偶然发现更有价值的花蜜来源。 蜂巢的资源只会被浪费。 将侦察兵派往已知搜索区域的邻域更有用,这样坐标就不会分散,而是专门集中在可能的花蜜来源区域。

如果这些区域彼此相交,则必须偏转中心,令这些区域仅接触边界。 如图例 2 所示。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

图例 2. 等级较低的区域应偏转

区域的排位并非严格设定的,而是动态形成的。 侦察蜂的发现会被分配到它们飞过区域的附近地区。 如果发现更有价值的食物来源,该区域的中心将转移到那里。 它甚至可能成为新的最佳花蜜采集中心。 其余区域现在将相对于它偏转。 换言之,它们沿排位链并相对于它偏移。

传递信息的方法,称为蜂之舞,是整个蜂巢战略的基本要素。 蜂巢的可用资源理应合理地分配到采集区域,那么遣派的蜜蜂数量应与区域的价值成正比。 这意味着相同数量的蜜蜂将被遣派到同等价值的区域。

我们继续讨论算法本身。 下面列出了执行步骤:

  1. 所有蜜蜂都作为侦察员沿着搜索空间随机飞行。

  2. 测量来自每只蜜蜂采集的花蜜量。

  3. 分拣蜜蜂。

  4. 根据从蜜蜂获得的花蜜量信息分配区域。

  5. 将工蜂遣派到该区域。 该区域的花蜜越多,遣派的蜜蜂就越多。

  6. 在随机选择的区域附近派遣侦察蜂。

  7. 测量来自每只蜜蜂那里采集到的花蜜量。

  8. 按花蜜量对区域进行排名。

  9. 重复上述步骤 直到满足停止准则。

为了便于直观感知,赫兹期货量化制作了算法的框图,如图例 3。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

图例 3. 算法框图

赫兹期货量化更详细地讲述蜂群算法代码。

一只蜜蜂是算法的基本逻辑单元。 它可以通过结构来讲述。 您可能还记得,蜜蜂的位置是由坐标、与采集的花蜜区域的隶属关系、以及花蜜的数量来设置的。 那么,蜂巢的蜜蜂可由一个数组表示。 每个都可以据其索引来访问。

 
 

//—————————————————————————————————————————————————————————————————————————————— struct S_Bee { double c []; //coordinates int aInd; //area index double n; //nectar }; //——————————————————————————————————————————————————————————————————————————————

第二个更大的逻辑单元是花蜜采集区域。 它由花蜜最集中的中心点,以及决定该区域价值的花蜜量来定义。 在最高等级的区域(列表中的第一个),中心坐标和花蜜的最高浓度重合。 而对于列表中排名第二和更低的区域,它们可能不一致,因为它们被转移了。 该区域的初始化以重置花蜜量指标,并将坐标分配给优化函数的相应编号的参数。

 
 

//—————————————————————————————————————————————————————————————————————————————— struct S_Area { void Init (int coordinatesNumber) { n = -DBL_MAX; ArrayResize (cC, coordinatesNumber); ArrayResize (cB, coordinatesNumber); } double cC []; //center coordinates double cB []; //best coordinates double n; //nectarAmount }; //——————————————————————————————————————————————————————————————————————————————

赫兹期货量化将蜜蜂的舞蹈描述为一个结构,其数组将与区域的数量相对应。

 
 

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

我将蜂巢描述为一个类,设置搜索区域、蜜蜂、最佳坐标、以及在所有迭代中发现的最大花蜜量。 此外,针对蜜蜂和区域进行分类,以及移动蜜蜂和彼此相对区域的所有必要方法均在此处定义。 在此,赫兹期货量化可以看到以前算法中已经熟悉的函数声明:生成随机均匀分布的数字,缩放到一个范围,然后从范围内选择一个数字并带有步长。

 
 

//—————————————————————————————————————————————————————————————————————————————— class C_AO_ABC //Bees Hive { //============================================================================ public: S_Area areas []; //nectar collection areas public: double rangeMax []; //maximum search range public: double rangeMin []; //manimum search range public: double rangeStep []; //step search public: S_Bee bees []; //all the bees of the hive public: double cB []; //best coordinates public: double nB; //nectar of the best coordinates public: void InitHive (const int coordinatesP, //number of opt. parameters const int beesNumberP, //bees number const int workerBeesNumberP, //worker bees number const int areasNumberP, //areas number const double collectionRadiusP, //collection radius const double scoutAreaRadiusP); //scout area radius public: void TasksForBees (); public: void CollectingNectar (); //============================================================================ private: void BeeFlight (double &cC [] , S_Bee &bee); private: void ScoutBeeFlight (double &cC [] , S_Bee &bee); private: void MarkUpAreas (); private: void SortingBees (); private: void SortingAreas (); 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: int coordinates; //coordinates number private: int beesNumber; //the number of all bees private: int workerBeesNumber; //worker bees number private: int areasNumber; //areas number private: S_Bee beesT []; //temporary, for sorting private: S_Area areasT []; //temporary, for sorting private: int indA []; //array for indexes when sorting private: double valA []; //array for nectar values when sorting private: int indB []; //array for indexes when sorting private: double valB []; //array for nectar values when sorting private: double areasRadius []; //radius for each coordinate private: double scoutRadius []; //scout radius for each coordinate private: double collectionRadius; //collection radius private: double scoutAreaRadius; //scout area radius private: double hypersphereRadius; //hypersphere radius private: double distHyperspCenters; //distance hyperspheres centers private: double scoutHyperspRadius; //scout hypersphere radius private: bool scouting; //scouting flag private: S_BeeDance beeDance []; //bee dance }; //——————————————————————————————————————————————————————————————————————————————

每次新优化都必须从类初始化开始。 整个蜂巢和蜜蜂单体,以及区域的花蜜量值均被重置。

 
 

//—————————————————————————————————————————————————————————————————————————————— void C_AO_ABC::InitHive (const int coordinatesP, //number of opt. parameters const int beesNumberP, //bees number const int workerBeesNumberP, //worker bees number const int areasNumberP, //areas number const double collectionRadiusP, //collection radius const double scoutAreaRadiusP) //scout area radius { MathSrand (GetTickCount ()); scouting = false; nB = -DBL_MAX; coordinates = coordinatesP; beesNumber = beesNumberP; workerBeesNumber = workerBeesNumberP; areasNumber = areasNumberP < 3 ? 3 : areasNumberP; collectionRadius = collectionRadiusP; //collection radius scoutAreaRadius = scoutAreaRadiusP; //scout area radius ArrayResize (areas, areasNumber); ArrayResize (areasT, areasNumber); for (int i = 0; i < areasNumber; i++) { areas [i].Init (coordinates); areasT [i].Init (coordinates); } ArrayResize (beeDance, areasNumber); ArrayResize (rangeMax, coordinates); ArrayResize (rangeMin, coordinates); ArrayResize (rangeStep, coordinates); ArrayResize (cB, coordinates); ArrayResize (indA, areasNumber); ArrayResize (valA, areasNumber); ArrayResize (areasRadius, coordinates); ArrayResize (scoutRadius, coordinates); for (int i = 0; i < coordinates; i++) { areasRadius [i] = (rangeMax [i] - rangeMin [i]) * collectionRadius; scoutRadius [i] = (rangeMax [i] - rangeMin [i]) * scoutAreaRadius; } double sqr = 0.0; for (int i = 0; i < coordinates; i++) sqr += areasRadius [i] * areasRadius [i]; hypersphereRadius = MathSqrt (sqr) * collectionRadius; distHyperspCenters = hypersphereRadius * 2.0; sqr = 0.0; for (int i = 0; i < coordinates; i++) sqr += scoutRadius [i] * scoutRadius [i]; scoutHyperspRadius = MathSqrt (sqr) * scoutAreaRadius; ArrayResize (indB, beesNumber); ArrayResize (valB, beesNumber); ArrayResize (bees, beesNumber); ArrayResize (beesT, beesNumber); for (int i = 0; i < beesNumber; i++) { ArrayResize (bees [i].c, coordinates); ArrayResize (beesT [i].c, coordinates); bees [i].n = -DBL_MAX; beesT [i].n = -DBL_MAX; } } //——————————————————————————————————————————————————————————————————————————————

最简单也是开放的类方法就是给蜜蜂分派任务。 这里的一切都很简单。 如果有尚未探索区域,则重置整个蜂巢的花蜜值,并启动区域标记。 我们在每个世代上调用该方法,直到获得适应度函数的值。

 
 

//—————————————————————————————————————————————————————————————————————————————— void C_AO_ABC::TasksForBees () { if (!scouting) { nB = -DBL_MAX; } MarkUpAreas (); } //——————————————————————————————————————————————————————————————————————————————

第二个公开方法在每个世代调用。 在获取适应度函数的值后执行启动。 在这种情况下,如果尚未进行探索,赫兹期货量化按花蜜值对蜜蜂进行排序,并将列表中第一批蜜蜂的坐标和花蜜数量复制到相应的区域中。 如果地点勘探已经进行,那么我们复制采集花蜜区域的坐标和花蜜数量,前提是结果有所改善。 此外,更新整个蜂巢的最佳结果。

 
 

//—————————————————————————————————————————————————————————————————————————————— void C_AO_ABC::CollectingNectar () { if (!scouting) { SortingBees (); for (int a = 0; a <areasNumber; a++) { ArrayCopy (areas [a].cB, bees [a].c, 0, 0, WHOLE_ARRAY); areas [a].n = bees [a].n; } scouting = true; } else { //transfer the nectar to the hive--------------------------------------------- for (int b = 0; b < beesNumber; b++) { if (bees [b].n > areas [bees [b].aInd].n) { ArrayCopy (areas [bees [b].aInd].cB, bees [b].c, 0, 0, WHOLE_ARRAY); areas [bees [b].aInd].n = bees [b].n; } if (bees [b].n > nB) { ArrayCopy (cB, bees [b].c, 0, 0, WHOLE_ARRAY); nB = bees [b].n; } } SortingAreas (); } } //——————————————————————————————————————————————————————————————————————————————

MarkUpAreas () 方法值得详细研究。 赫兹期货量化将代码分解成多个部分。

在探索区域之前,没有关于寻找花朵采集花蜜的任何信息,赫兹期货量化将派遣所有蜜蜂进行初步探索。 在这个阶段,所有的蜜蜂都扮演着侦察员的角色。 由于没有关于花蜜的信息,赫兹期货量化向随机方向派遣侦察员,生成的随机数均匀分布在坐标范围内。

 
 

//if the areas is not scouting - send all the bees to scouting---------------- if (!scouting) { for (int b = 0; b < beesNumber; b++) { for (int c = 0; c < coordinates; c++) { bees [b].c [c] = RNDfromCI (rangeMin [c], rangeMax [c]); bees [b].c [c] = SeInDiSp (bees [b].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } }

探索区域后,有必要将花蜜浓度最大的坐标复制到该区域的中心。 换言之,有必要将该区域移到更好的位置。 执行此操作后,赫兹期货量化需要确保该区域不与较高排位的区域相交。 赫兹期货量化可以通过测量区域中心之间的距离来检测区域的交点。 如果中心之间的距离小于两个半径(算法参数之一),则区域相交。 如果检测到相交,则将该区域转移到两个半径距离的地点,而最佳结果的坐标(最大花蜜浓度的坐标)保留在相同位置。 因此,这些区域持续变动。 最好的区域迫使其余区域转移。 其余区域,在偏转的同时,可以到达更丰富的食物来源,在排序后成为最好的,这在下一个方法中发生。

 
 

for (int s = 0; s < areasNumber; s++) { //move the center of the area to the best point in with more nectar------- ArrayCopy (areas [s].cC, areas [s].cB, 0, 0, WHOLE_ARRAY); //ordinary area----------------------------------------------------------- if (s != 0) { //check if there is no intersection of a region with a region of higher rank //measure the distance from the centers of the regions double centersDistance = 0.0; for (int c = 0; c < coordinates; c++) centersDistance += pow (areas [s].cC [c] - areas [s - 1].cC [c], 2.0); centersDistance = MathSqrt (centersDistance); //the areas intersect, then need to move the current area if (centersDistance < distHyperspCenters) { double incrementFactor = (distHyperspCenters - centersDistance) / centersDistance; double coordDistance = 0.0; for (int c = 0; c < coordinates; c++) { coordDistance = areas [s].cC [c] - areas [s - 1].cC [c]; areas [s].cC [c] = areas [s].cC [c] + (coordDistance * incrementFactor); areas [s].cC [c] = SeInDiSp (areas [s].cC [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } }

这就是蜜蜂跳舞的地方。 依据有关区域的方向和花蜜数量的信息,并应用随机分量,赫兹期货量化标记随机数的分布区域,如此令蜜蜂在下一次迭代中选择区域的概率与该区域的花蜜量成正比。 简而言之,在数字线上,赫兹期货量化绘制了段,其长度对应于面积最差的每个区域的花蜜值之间的差值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值