股票量化交易软件:种群优化算法萤火虫算法(FA)

1. 概述
自然界一直是许多元启发式算法的灵感来源。 它设法在没有提示的情况下,基于个体经验找到问题的解决方案。 自然选择和适者生存是创建早期元启发式算法的主要动机。 在自然界中,动物以多种方式相互交流。 萤火虫则是利用眨眼的能力进行交流。 大约有 2000 种萤火虫,都拥有自己特殊的闪烁图案。 它们通常会产生具有特定图案的短闪烁。 光亮及其强度成为称为生物发光的生化过程的成果。 据信,这种闪烁的主要功能是求偶和吸引潜在的受害者。 一些热带萤火虫可以同步它们的闪烁,从而展示了生物自组织的一个例子。 光亮的强度作为与其光源距离的函数,遵循平方反比定律,因此来自萤火虫的闪烁光线会导致它周围的萤火虫在闪烁的视线范围内做出反应。
受萤火虫行为启发的种群优化算法有两种变体:萤火虫算法,和萤火虫群优化(GSO)算法。 萤火虫(firefly)和发光甲虫(glowworms)的主要区别在于后者是无翅的。 在本文中,赫兹量化交易软件将研究前一种类的优化算法。
2. 算法说明
萤火虫算法(F-算法)由 X-Sh. Yang 于 2007 年在英国剑桥大学提出,并立即引起了优化研究人员的注意。 萤火虫算法是群体智能算法家族的一部分,最近在解决优化问题方面取得了令人印象深刻的成果。 特别是,萤火虫算法在求解连续和离散优化问题的能力。 萤火虫算法基于真实萤火虫的闪烁特性,有三条规则。 规则如下:
所有萤火虫都会朝着更有吸引力和更明亮的对应物移动。
萤火虫的吸引力程度与其亮度成正比,由于空气吸收光线的事实,随着与另一只萤火虫的距离增加,亮度会降低。 故此,在任何两只闪烁的萤火虫之间,不太亮的萤火虫会向较亮的萤火虫移动。 如果没有更亮或更具吸引力的对应物,则萤火虫将随机移动。
萤火虫的亮度或光线强度由问题的目标函数的值决定。
最初,在算法开始时,所有萤火虫都随机分散在整个搜索空间当中。 然后,该算法根据两个阶段判定最佳分区:
光线强度的变化 — 萤火虫在其当前位置的亮度反映在其适应性值中,朝着有吸引力的萤火虫移动。
萤火虫通过观察邻近萤火虫的光线强度来改变其位置。
现在,赫兹量化软件可以更详尽地深入了解萤火虫优化的复杂性。 该算法本质上如图例 1 所示。

编辑切换为居中
图例 1. 搜索空间中的萤火虫。 能见度随着距离的增加而降低
搜索原理背后的主要思路是随着萤火虫之间距离的增加,能见度呈非线性降低。 如果没有这种非线性关系,每只萤火虫都会确定性地向更明亮的光源移动。 然而,正如我们在图例 1 中看到的,萤火虫不会选择其最亮的近邻,因为由于环境对光线的吸收,它发出的光线很难被注意到。 取而代之,它选择了一个不太明亮的对应物(尽管是其环境中最亮的)。 此特征解释了算法划分为较小群落的良好能力。 由于远距离光吸收的非线性函数,这现象会很自然地发生。 在下面的图例 2 中,我们可以看到具有不同 gamma 介质吸收系数值的算法的可见性与距离的函数,这是算法参数之一。

编辑切换为居中
图例 2. 介质透明度与距离f(x) 的函数,其中 gamma 透明度系数分别等于 1.0、0.2、0.05、0.01。
当 gamma 趋于无穷大时,环境变得不透明;当 gamma 为零时,环境是完全透明的;每只萤火虫在搜索空间中的任何距离都能看到对方。 如果 gamma = 0.0 会发生什么? 所有的萤火虫都会飞到最明亮的相对位置,汇聚到某个非最佳点。 如此,算法不会收敛停留在某个局部极值。 如果环境完全不透明,会发生什么情况? 萤火虫不会看到比自己更有吸引力的同类。 根据算法作者提出的概念,看不到比自己更好的同类,那么萤火虫就会随机移动。 该算法将退化为随机搜索。 在我们的算法分类评级表格中,随机搜索算法排在最后。
我们来深入分析算法,并考虑描述萤火虫运动的方程。 能见度与距离的函数是计算所谓吸引力指数的基础:
attractiveness = fireflies [k].f / (1.0 + gamma * distance * distance);
其中: attractiveness - 吸引力,不言自明 gamma - 环境不透明度系数 distance - 萤火虫之间的欧氏距离 fireflies [k].f - 第 k 只萤火虫的光线强度
该方程清楚地表明,吸引力函数直接取决于问题的维度和距离值的限制,因此该算法的作者建议为特定的优化问题选择透明度系数。 我认为,在事先不知算法将如何表现的情况下就这样做,既不方便又耗时;因此我认为有必要对 0 到 20 范围内的距离值进行规范化。 为达此目的,应用我们在其它算法中反复使用的 Scale() 函数。 在计算吸引力之前,“distance” 的转换如下所示:
distance = Scale (distance, 0.0, maxDist, 0.0, 20.0, false);
其中:
maxDist — 在一对萤火虫之间的最大欧几里得距离
在这种情况下,萤火虫的吸引力将不取决于问题的维度,也无需为特定的优化问题选择 gamma 系数。 吸引力函数判定每只萤火虫将做出什么样的配偶选择。 这个选择是有严格判定的。 萤火虫相互吸引力的影响决定了 beta 系数(算法的第二个参数)。 如果在每次迭代中萤火虫已经提前确定了相应的选择,如何确保算法的搜索能力? 为此,引入了随机向量分量,和第三个算法参数(alpha)。 萤火虫的复杂行为关系如下所示:
fireflies [i].c [c] = Xj + beta * (Xi - Xj) + alpha * r * v [c];
其中: fireflies [i].c [c] - 第 i 个萤火虫的第 c 个坐标 beta - 萤火虫吸引力影响系数 alpha - 当萤火虫移动时影响随机分量的系数,给出与移动目标的偏差 r - 范围 [-1.0;1.0] 内的随机数 v[c] - 向量分量,通过第 c 个坐标表征搜索范围极点之间的距离 Хj - 萤火虫对中的对应坐标,其将有运动 Xi - 计算运动的萤火虫的对应坐标
现在是时候讲述算法代码了。 它相对简单。 我们来研究细节。
萤火虫将用一个简单的结构来描述 S_Firefly,该结构具有两个组成部分,即 c[] - 坐标,f - 萤火虫的亮度(适应度函数)。 鉴于对于每只萤火虫,在相应的迭代中只有单一个体,它移动后会形成新的配对,因此在计算下一次移动时,我们不会冒覆盖坐标的风险。 为此目的,我将引入下面研究的特殊结构。
萤火虫算法由 C_AO_FA 类进行定义。 这里有三个公开方法,其中一个是用于初始初始化的 Init(),两个需要在每次迭代时调用的公开方法 — Flight() 和 Luminosity(),私密帮助方法,和存储参数常量的成员。
来研究每次迭代时调用的第一个公开方法 — Flight()。 算法的主要逻辑集中在该方法当中,因此有必要详尽地研究它。 'luminosity' 变量当作一个标志,允许我们判定算法是处于第一次迭代,还是在后续迭代中运行。 如果标志尚未设置,则需要按照均匀分布将萤火虫随机分布到坐标空间之中。 在执行此操作的同时,我们为每个坐标设置位移向量,并立即计算萤火虫之间可以达到的最大可能欧氏距离(如前所述,这对于规范化萤火虫之间的距离是必要的,以避免环境透明度系数对问题维度的依赖性)。 完成这些操作后,启用 “luminosity” 标志。
if (!luminosity) { fB = -DBL_MAX; //-------------------------------------------------------------------------- double summCoordinates = 0.0; for (int c = 0; c < params; c++) { v [c] = rangeMax [c] - rangeMin [c]; summCoordinates += pow (v [c], 2.0); } maxDist = pow (summCoordinates, 0.5); //-------------------------------------------------------------------------- for (int s = 0; s < swarmSize; s++) { for (int k = 0; k < params; k++) { fireflies [s].c [k] = RNDfromCI (rangeMin [k], rangeMax [k]); fireflies [s].c [k] = SeInDiSp (fireflies [s].c [k], rangeMin [k], rangeMax [k], rangeStep [k]); } } luminosity = true; }
从第二次及苏随后的迭代中,在第一次迭代中随机发送出去的萤火虫开始发光(适应度函数开始针对它们进行计算)之后,可以计算出每只萤火虫的吸引力程度。 为此,我们需要针对所有可能的萤火虫配对,计算它们之间的欧几里得距离。 为此,只需将坐标差的平方相加,然后取它们总和的平方根。 计算出的距离会应用到吸引力计算方程。 这就是我们为何每只萤火虫仅取可能的配对。 判定所有萤火虫的最大亮度。 这是判定最亮萤火虫所需的做法,因为不可能找到一对萤火虫,且独自在空间中徘徊。 好吧,也许,在下一次迭代中会更幸运。
//measure the distance between all------------------------------------------ for (int i = 0; i < swarmSize; i++) { att [i].a = -DBL_MAX; for (int k = 0; k < swarmSize; k++) { if (i == k) continue; summCoordinates = 0.0; for (int c = 0; c < params; c++) summCoordinates += pow (fireflies [i].c [c] - fireflies [k].c [c], 2.0); distance = pow (summCoordinates, 0.5); distance = Scale (distance, 0.0, maxDist, 0.0, 20.0, false); attractiveness = fireflies [k].f / (1.0 + gamma * distance * distance); if (attractiveness > att [i].a) { att [i].a = attractiveness; att [i].i = k; } if (fireflies [i].f > maxF) maxF = fireflies [i].f; } }
Flight() 方法的这一部分代码负责萤火虫的飞行。 对于那些不幸的萤火虫,其亮度大于所有其它萤火虫,计算方式略有不同。 我们添加了一个移动向量到其当前位置,即 alpha 系数乘以随机数 [-1.0;1.0]。 理论上,在算法中,这一行动是对最佳解的附加研究,期望它能更好,但是,正如我们稍后将看到的,这种技术将被证明无甚大用。 在此阶段,我们研究算法的经典版本。
对于所有其它萤火虫,若已经找到配对萤火虫,计算运动时将包括朝向相应配对的萤火虫移动(通过添加的随机分量,我之前提到过)。
