English Русский Español Deutsch 日本語 Português
preview
密码锁算法(CLA)

密码锁算法(CLA)

MetaTrader 5示例 | 28 十一月 2024, 11:11
519 0
Andrey Dik
Andrey Dik

内容

1. 概述
2. 算法实现
3. 测试结果


1. 概述

密码锁,也被称为数字锁或组合锁,是用来控制房间、保险箱、橱柜或其他物品访问权限的安全机制。它们与普通锁的不同之处在于,不是使用钥匙来开启,而是需要输入特定的数字组合。

密码锁通常配备有键盘、特殊圆筒或其他旋转机制,允许用户输入代码序列。一旦输入了正确的组合,密码锁就会激活解锁机制,允许用户打开门或访问保险箱的内容。用户可以设置自己的代码,也可以使用提供的代码来打开锁。

密码锁优势:

  • 安全性。密码锁可以提供高度的安全性,尤其是密码需要定期更换的情况。
  • 便利性。无需携带钥匙,这使得密码锁使用起来非常方便。
  • 可设置多个密码。一些型号的密码锁允许为不同用户或不同时间段设置多个不同的密码。

密码锁被广泛应用于多个领域,包括家庭安全、商业建筑、酒店、学校、办公室以及其他需要访问控制的机构。将密码锁的概念应用于优化算法中可能是一个有趣的想法。密码锁在优化算法中的一种可能应用是创建一个系统,该系统利用密码锁的原理来解决优化问题,例如寻找机器学习问题中的最优参数值,或其他优化问题。

密码锁的操作原理,即输入正确的数字组合以解锁,与优化算法中寻找最优解的机制相似,后者通过迭代改变参数并评估其效率来找到最优解。

例如,可以想象一个使用密码锁原理的优化算法如下:

  1. 参数组合。待优化的参数可以表示为输入的一个“组合”。
  2. 验证组合的有效性。算法可以改变参数值并评估其效率,这类似于用户向密码锁输入不同的组合以验证其有效性。
  3. 最优解即解锁。当算法找到了最优参数值时,这可以视为“解锁”最优解。

因此,密码锁启发了我开发一种优化算法,该算法可用于寻找各种问题中的最优解,包括机器学习和交易系统开发等领域。


2. 算法实现

让我们将一群智能体想象成一群锁,其中每把锁代表一个问题的解决方案。接下来,我们可以为密码锁算法勾勒出一个近似的伪代码框架:

1. 初始化:
创建一个大小为popSize的锁数组。每把锁具有一组coords圆盘,而每组包含lockDiscs个圆盘。
2. 选择锁的组合:
如果这是第一步,则将每把锁的每一组中的每个圆盘初始化为0到9之间的一个随机数。
否则,对于每把锁:
- 如果一个随机数小于copyProb,则从随机选择的一把锁中复制一组圆盘。
- 否则,对于每组圆盘:
- 如果一个随机数小于rotateProb,则将圆盘设置为0到9之间的一个随机数。 - 否则,从随机选择的锁中复制圆盘。
3. 评估锁组合的质量:
更新每个锁组合的质量。
找出组合质量最好的锁,并在必要时更新全局最佳解决方案。
将所有锁复制到公共锁篮中。
按适应度对锁篮中的锁进行排序。
4. 重复步骤2和3,直到达到指定的迭代次数或满足停止准则。

这个概念相当吸引人,但在某些方面仍然存在疑问。特别是,锁中的组合密码如何能够代表一个问题的解决方案,这一点尚不完全明确。为了加深理解,通过一个具体的示例来说明,将会非常有帮助。

让我们想象一下,我们用密码锁的形式来表示一个问题的解决方案,其中我们需要优化一个或多个参数。在这种情况下,每个参数都可以表示为一组数字的组合,每个数字都在一个独立的圆盘上。圆盘的数量可以是任意的。这被视为算法的一个外部参数。因此,每个参数都由一组带有数字标签的圆盘来表示。

例如,如果一个任务参数有一组9个圆盘,每个圆盘上的数字从0到9,那么组合可以是000000000到999999999之间的任何数字。我们将得到的数字缩放到相应参数“最小值”到“最大值”的范围内。因此,如果我们有三个需要优化的参数,那么我们的密码锁将有3 x 9 = 27个数字圆盘。图例1展示了单个参数的编码机制。

代码

图例1. 通过数字代码解码将任务参数变成实际值

在优化算法中,诸如交叉和变异等算子,基于代码锁的思想被整合到CLA优化算法中。

1. 交叉。遗传算法中的交叉操作旨在将两个父本的遗传物质结合起来,从而创造出子代。

  • 在密码锁背景下,我们可以将交叉想象成从不同锁的盘值中组合出一种新的编码任务参数组合。
  • 这个过程为算法提供了探索参数新组合的可能性,类似于用户可以在密码锁上尝试不同的数字组合,并且仍然可以在不同的锁上使用最成功的数字组合。

2. 变异。遗传算法中的变异是指遗传物质的随机变化,旨在增加种群的多样性。

  • 在密码锁背景下,变异可以理解为随机旋转密码锁盘到任意数字位置,从而改变密码锁的组合。
  • 这个过程有助于算法在整个解空间中探索新的参数组合,并避免陷入局部最优解。

一般来说,将交叉和突变整合到优化算法中,可以增加解的多样性,加速收敛到最优解,并有助于避免过早收敛。这种方法在处理庞大的搜索空间和复杂目标函数的优化问题时非常有用。事实上,与遗传算子进行类比,我们除了旋转盘之外别无选择。

为了解决这个问题,我们需要选择密码锁上正确的数字组合。我们需要旋转盘以找到能够打开锁的正确密码组合。在遗传算法中,“旋转”基因中的二进制代码值得到某个值的概率是50%(即0或1),与遗传算法不同,在组合锁算法中,我们可以在盘旋转策略中使用概率分布。让我们考虑几种选择。

我们可以使用高斯分布来变异组合参数,即每个参数都变为一个从正态分布(高斯分布)中随机选择的值。这样可以在一定程度上对参数进行随机改变,同时仍然保持其当前值。

使用高斯分布实行变异是有用的,因为它可以控制参数变化的程度。参数可以变为接近当前值的较小值,这有助于保留当前解决方案的良好属性,而变异的随机性则允许算法探索搜索空间内的新区域。

因此,使用高斯分布实行变异可以在探索新解决方案与保持当前解决方案的良好属性之间取得平衡,这将有助于在复杂的参数空间中高效搜索最优解。

我们还可以使用幂律分布来实行变异过程。与高斯分布不同,幂律分布的尾部更重,这意味着出现较大参数变化的可能性更大,这在需要更彻底地探索参数空间的情况下可能是有用的。幂律分布可以帮助算法“跳出”局部陷阱。

我们也可以选择第三种方案——均匀分布,该方案使得选择锁盘上任意数字的概率相等。

现在,我们会从理论部分转向编写代码和实践研究。

在代表问题解决方案的智能体CLA算法中,我们使用S_CLA_Agent结构来描述锁。以下是其主要组成部分:

  • f表示一个智能体的适应度。它被初始化为 -DBL_MAX,这是 double 类型所能取到的最小值。
  • struct S_Lock是一个嵌套结构,包含了一个名为 lock的数组。这个数组用于存储单个任务参数(正在被优化)的代码组合。
  • S_Lock code[]S_Lock结构体数组。整个数组构成了一个“锁”。
  • void Init (int coords, int lockDiscs)是一个初始化函数。它接受两个参数:coords 定义了参数集的数量,而lockDiscs定义了每个参数集中的盘片数量。在函数内部,初始化code数组。

总体来说,该结构代表了 CLA优化算法中的一个智能体。每个智能体都有自己的适应度和锁组合描述,这些将在执行算法的过程中逐渐优化。

//——————————————————————————————————————————————————————————————————————————————
struct S_CLA_Agent
{
    double f;  //fitness

    struct S_Lock
    {
        int lock [];
    };

    S_Lock code [];


    void Init (int coords, int lockDiscs)
    {
      f = -DBL_MAX;

      ArrayResize (code, coords);

      for (int i = 0; i < coords; i++)
      {
        ArrayResize (code [i].lock, lockDiscs);
      }
    }
};
//——————————————————————————————————————————————————————————————————————————————

现在,我们来描述从C_AO类派生的C_AO_CLA类。主要类组件如下:

  • C_AO_CLA () - 类构造函数,用于初始化类对象。在构造函数内部,诸如 popSize(种群大小)、lockDiscs(锁盘片数量)、copyProb(复制概率)、rotateProb(旋转概率)和 params(参数数组)等参数被初始化。
  • SetParams() - 根据params数组中的值设置算法参数。
  • Init ()是一个初始化函数,它接受搜索范围和迭代次数作为参数。
  • Moving ()Revision ()是用于执行算法主要逻辑的函数。
  • lockDiscscopyProbrotateProb 用于存储算法参数的变量。
  • S_CLA_Agent agent[]是智能体的一个数组。每个智能体都是 S_CLA_Agent结构体的一个对象。
  • maxLockNumberS_CLA_Agent parents[]S_CLA_Agent parTemp[]是在类的内部使用的私有变量和数组。
  • ArrayToNumber ()LockToDouble ()是私有方法,分别用于将代码组合数组转换为数字,以及将锁转换为浮点数。
//——————————————————————————————————————————————————————————————————————————————
class C_AO_CLA : public C_AO
{
  public: //--------------------------------------------------------------------
  ~C_AO_CLA () { }
  C_AO_CLA ()
  {
    ao_name = "CLA";
    ao_desc = "Code Lock Algorithm";
    ao_link = "https://www.mql5.com/ru/articles/14878";

    popSize     = 100;   //population size

    lockDiscs   = 8;     //lock discs
    copyProb    = 0.8;   //copying probability
    rotateProb  = 0.03;  //rotate disc probability

    ArrayResize (params, 4);

    params [0].name = "popSize";     params [0].val = popSize;

    params [1].name = "lockDiscs";   params [1].val = lockDiscs;
    params [2].name = "copyProb";    params [2].val = copyProb;
    params [3].name = "rotateProb";  params [3].val = rotateProb;
  }

  void SetParams ()
  {
    popSize    = (int)params [0].val;

    lockDiscs  = (int)params [1].val;
    copyProb   = params      [2].val;
    rotateProb = params      [3].val;
  }

  bool Init (const double &rangeMinP  [], //minimum search range
             const double &rangeMaxP  [], //maximum search range
             const double &rangeStepP [], //step search
             const int     epochsP = 0);  //number of epochs

  void Moving   ();
  void Revision ();
  void Injection (const int popPos, const int coordPos, const double value);

  //----------------------------------------------------------------------------
  int    lockDiscs;    //lock discs
  double copyProb;     //copying probability
  double rotateProb;   //rotate disc probability

  S_CLA_Agent agent [];

  private: //-------------------------------------------------------------------
  int maxLockNumber; //max lock number

  S_CLA_Agent parents [];
  S_CLA_Agent parTemp [];

  int    ArrayToNumber (int &arr []);
  double LockToDouble  (int lockNum, int coordPos);
};
//——————————————————————————————————————————————————————————————————————————————

C_AO_CLA类中定义Init方法。此方法使用给定的搜索范围和迭代次数来初始化算法。各步骤的描述如下:

1. if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false; - 在指定的搜索范围内调用StandardInit函数。如果初始化失败,函数返回'false'。

2. ArrayResize (agent, popSize); - 将'agent'数组调整为popSize种群规模。

3. for (int i = 0; i < popSize; i++) agent [i].Init (coords, lockDiscs); - 该循环使用指定的coords坐标数量和lockDiscs锁盘数量初始化种群中的每个智能体。

4. ArrayResize (parents, popSize * 2); ArrayResize (parTemp, popSize * 2); - 将parentsparTemp数组的大小调整为两个种群的大小。

5. for (int i = 0; i < popSize * 2; i++) { parents [i].Init (coords, lockDiscs); parTemp [i].Init (coords, lockDiscs); } - 该循环用于初始化parentsparTemp数组中的每个父类个体和临时父类个体。

6. maxLockNumber = 0; for (int i = 0; i < lockDiscs; i++) { maxLockNumber += 9 * (int)pow (10, i); } - 该循环使用锁盘数量(lockDiscs)来计算maxLockNumber锁组合中的最大数字。

7. return true; - 如果之前所有操作都成功,该函数返回'true'。

该函数在CLA代码锁优化算法中初始化agent和parent ,并根据锁盘的数量设置锁组合的最大数量。

//——————————————————————————————————————————————————————————————————————————————
bool C_AO_CLA::Init (const double &rangeMinP  [], //minimum search range
                     const double &rangeMaxP  [], //maximum search range
                     const double &rangeStepP [], //step search
                     const int     epochsP = 0)   //number of epochs
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //----------------------------------------------------------------------------
  ArrayResize (agent, popSize);
  for (int i = 0; i < popSize; i++) agent [i].Init (coords, lockDiscs);

  ArrayResize (parents, popSize * 2);
  ArrayResize (parTemp, popSize * 2);

  for (int i = 0; i < popSize * 2; i++)
  {
    parents [i].Init (coords, lockDiscs);
    parTemp [i].Init (coords, lockDiscs);
  }

  maxLockNumber = 0;
  for (int i = 0; i < lockDiscs; i++)
  {
    maxLockNumber += 9 * (int)pow (10, i);
  }

  return true;
}
//——————————————————————————————————————————————————————————————————————————————

数字组合锁的选择在C_AO_CLA类的Moving 方法中已描述。其遵循如下过程:

  • val  = 0.0; code = 0; pos  = 0; - 初始化该方法中需要使用的变量。
  • if (!revision) {...} - 如果revision是'false',执行代码块。在这段代码中,用随机值初始化智能体和父类。 
  • 然后,为每个智能体和父类计算code val值,并使用这些值来更新智能体的坐标。之后,将revision设置为'true',表示函数执行完毕。
  • for (int i = 0; i < popSize; i++) {...} - 当revision为'true'时,执行代码块。在该代码块内部,对智能体进行更新。如果生成的随机数小于copyProb,则将其中一个父类的锁代码复制到智能体上。否则,将智能体的锁代码更新为一个随机值或其中一个父类的锁代码。 
  • 然后,为每个智能体重新计算codeval值。这些值用于更新智能体的坐标。

在CLA优化算法中,用该函数更新智能体。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_CLA::Moving ()
{
  double val  = 0.0;
  int    code = 0;
  int    pos  = 0;

  //----------------------------------------------------------------------------
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        for (int l = 0; l < lockDiscs; l++)
        {
          agent [i].code [c].lock [l] = u.RNDminusOne (10);
        }

        code = ArrayToNumber (agent [i].code [c].lock);
        val  = LockToDouble  (code, c);
        a [i].c [c] = u.SeInDiSp  (val, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }

    for (int i = 0; i < popSize * 2; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        for (int l = 0; l < lockDiscs; l++)
        {
          parents [i].code [c].lock [l] = u.RNDminusOne (10);
        }
      }
    }

    revision = true;
    return;
  }

  //----------------------------------------------------------------------------
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      if (u.RNDprobab () < copyProb)
      {
        int pos = u.RNDminusOne (popSize);
        ArrayCopy (agent [i].code [c].lock, parents [pos].code [c].lock, 0, 0, WHOLE_ARRAY);
      }
      else
      {
        for (int l = 0; l < lockDiscs; l++)
        {
          if (u.RNDprobab () < rotateProb)
          {
            //pos = u.RNDminusOne (popSize);
            //agent [i].code [c].lock [l] = (int)round (u.GaussDistribution (agent [i].codePrev [c].lock [l], 0, 9, 8));
            //agent [i].code [c].lock [l] = (int)round (u.PowerDistribution (agent [i].codePrev [c].lock [l], 0, 9, 20));
            agent [i].code [c].lock [l] = u.RNDminusOne (10);
          }
          else
          {
            pos = u.RNDminusOne (popSize);
            agent [i].code [c].lock [l] = parents [pos].code [c].lock [l];
          }
        }
      }

      code = ArrayToNumber (agent [i].code [c].lock);
      val  = LockToDouble  (code, c);
      a [i].c [c] = u.SeInDiSp  (val, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————
通常用C_AO_CLA类中的Revision方法更新全局解决方案。该方法执行以下操作:
  • ind = -1; - 初始化变量ind,用于追踪具有最优适应度的智能体的索引。
  • for (int i = 0; i < popSize; i++) {...} - 循环遍历种群中的每个智能体,并检查其适应度是否超过当前的最优适应度值fB。如果确实如此,则更新fB,并将ind设置为当前索引。
  • if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY); - 如果找到了具有最优适应度的智能体,则将其坐标复制到cB中。
  • for (int i = 0; i < popSize; i++) { agent [i].f = a [i].f; } - 循环根据a数组中的当前值更新每个智能体的适应度。
  • for (int i = 0; i < popSize; i++) { parents [i + popSize] = agent [i]; } - 该循环从popSize位置开始,将每个智能体复制到parents数组中,即父类种群的第二半部分。
  • u.Sorting (parents, parTemp, popSize * 2); - 使用字符串排序方法,将parTemp数组作为临时存储,对parents数组进行排序。
总体来说,此函数用于更新CLA算法中智能体的适应度和“父类”锁。这包括更新最优适应度值,并根据适应度对父类种群进行排序。
//——————————————————————————————————————————————————————————————————————————————
void C_AO_CLA::Revision ()
{
  //----------------------------------------------------------------------------
  int ind = -1;

  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ind = i;
    }
  }

  if (ind != -1) ArrayCopy (cB, a [ind].c, 0, 0, WHOLE_ARRAY);

  //----------------------------------------------------------------------------
  for (int i = 0; i < popSize; i++)
  {
    agent [i].f = a [i].f;
  }

  for (int i = 0; i < popSize; i++)
  {
    parents [i + popSize] = agent [i];
  }

  u.Sorting (parents, parTemp, popSize * 2);
}
//——————————————————————————————————————————————————————————————————————————————

ArrayToNumber方法将代码组合中的字符转换为一个数字。该方法具体如下:

  • result = 0; - 初始化用于存储结果的变量。
  • for (int i = 0; i < ArraySize (arr); i++) {...} - 循环遍历 arr 数组的每个元素。对于每个 arr[i] 元素,要将当前result值乘以 10 并加上 arr[i]。
  • return result; - 方法返回最终的result值。

总体来说,该方法通过将数组中的每个元素解释为数字十进制表示中的一位,从而将一个整数数组转换成为一个单一的整数。

例如,arr 输入数组(代码组合)的值:|0|3|1|5|7|0|。我们需要去掉组合中所有左边的零,并从3的值开始构成数字。所得数字是31570。如果组合中的所有单元格都包含零,则最终数字将为 0。

//——————————————————————————————————————————————————————————————————————————————
int C_AO_CLA::ArrayToNumber (int &arr [])
{
  int result = 0;
  for (int i = 0; i < ArraySize (arr); i++)
  {
    result = result * 10 + arr [i];
  }
  return result;
}
//——————————————————————————————————————————————————————————————————————————————

C_AO_CLA类中的LockToDouble方法将组合码的数字转换为优化参数。以下是该函数的功能说明:

  • LockToDouble (int lockNum, int coordPos) - 该方法需要获取两个参数:lockNum是锁的编号(即特定coordPos位置的锁编号),coordPos是坐标数组中的坐标位置(即优化参数的位置)。
  • return u.Scale (lockNum, 0, maxLockNumber, rangeMin [coordPos], rangeMax [coordPos]); - 该字符串返回lockNum 从 [0, maxLockNumber]范围缩放到[rangeMin [coordPos], rangeMax [coordPos]]范围而获得的值。

一般来说,该方法用于根据给定的范围将锁的编号转换为浮点数。换句话说,锁的编号被转换为优化任务的参数值。

//——————————————————————————————————————————————————————————————————————————————
double C_AO_CLA::LockToDouble (int lockNum, int coordPos)
{
  return u.Scale (lockNum, 0, maxLockNumber, rangeMin [coordPos], rangeMax [coordPos]);
}
//——————————————————————————————————————————————————————————————————————————————


3. 测试结果

CLA优化算法在测试函数上的结果表现优异。达到最大可能值的67.86%是一个极佳的结果。这证明了CLA算法在优化复杂函数方面体现出的高性能。

这些结果表明,CLA算法相当有效,可以成功应用于需要优化多维函数的各种问题中。其可扩展性和处理复杂问题的能力使其成为广泛解决优化问题的一种有效的工具。

CLA|Code Lock Algorithm|100.0|8.0|0.8|0.03|
=============================
5 Hilly's; Func runs: 10000; result: 0.9534490932631814
25 Hilly's; Func runs: 10000; result: 0.8710742215971827
500 Hilly's; Func runs: 10000; result: 0.375900385878165
=============================
5 Forest's; Func runs: 10000; result: 0.9894215656296362
25 Forest's; Func runs: 10000; result: 0.917091907561472
500 Forest's; Func runs: 10000; result: 0.3164221021938828
=============================
5 Megacity's; Func runs: 10000; result: 0.7969230769230768
25 Megacity's; Func runs: 10000; result: 0.693846153846154
500 Megacity's; Func runs: 10000; result: 0.19303076923077062
=============================
总分: 6.10716 (67.86%)

使用该算法在对测试函数操作的可视化过程中,可以注意到在低维函数上的结果存在一定的离散性。然而,随着任务参数数量的增加,结果的离散性逐渐消失。此外,从收敛曲线(红线)的形状可以看出,该算法在处理大规模问题(1000个参数)方面具有显著潜力。这条线以加速的方式增长。如果我们取消对适应度函数运行次数的限制(我们的测试规则),算法将继续逼近全局最优解。

Hilly值

  CLA在Hilly测试函数上

Forest值

  CLA在Forest测试函数上

Megacity

  CLA在Megacity测试函数上


代码锁算法在排行榜中位居第二位。在具有10个参数的夏普Forest函数中,CLA甚至能够超越排行榜的领头羊—BGA。所有测试函数的结果单元格颜色均为绿色(与表中列出的所有算法进行比较),这表明它在不同类型的任务上表现非常一致,在个别测试中没有出现明显的失败。” 

# AO 说明 Hilly值 Hilly最终值 Forest值 Forest最终值 Megacity (离散) Megacity最终值 最终结果 最大百分比
10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F) 10 p (5 F) 50 p (25 F) 1000 p (500 F)
1 BGA 二进制遗传算法 0,99989 0,99518 0,42835 2,42341 0,96153 0,96181 0,32027 2,24360 0,91385 0,95908 0,24220 2,11512 6,782 75,36
2 CLA 密码锁算法 0.95345 0.87107 0.37590 2.20042 0.98942 0.91709 0.31642 2.22294 0.79692 0.69385 0.19303 1.68380 6.107 67.86
3 (P+O)ES (P+O) 进化策略 0.92256 0.88101 0.40021 2.20379 0.97750 0.87490 0.31945 2.17185 0.67385 0.62985 0.18634 1.49003 5.866 65.17
4 CTA 彗星尾算法 0.95346 0.86319 0.27770 2.09435 0.99794 0.85740 0.33949 2.19484 0.88769 0.56431 0.10512 1.55712 5.846 64.96
5 SDSm 随机扩散搜索 M 0.93066 0.85445 0.39476 2.17988 0.99983 0.89244 0.19619 2.08846 0.72333 0.61100 0.10670 1.44103 5.709 63.44
6 ESG 社会群体的进化 0.99906 0.79654 0.35056 2.14616 1.00000 0.82863 0.13102 1.95965 0.82333 0.55300 0.04725 1.42358 5.529 61.44
7 SIA 模拟退火算法 0.95784 0.84264 0.41465 2.21513 0.98239 0.79586 0.20507 1.98332 0.68667 0.49300 0.09053 1.27020 5.469 60.76
8 TSEA 龟壳演化算法 0.96798 0.64480 0.29672 1.90949 0.99449 0.61981 0.22708 1.84139 0.69077 0.42646 0.13598 1.25322 5.004 55.60
9 DE 差分进化 0.95044 0.61674 0.30308 1.87026 0.95317 0.78896 0.16652 1.90865 0.78667 0.36033 0.02953 1.17653 4.955 55.06
10 BSA 鸟群算法 0.89306 0.64900 0.26250 1.80455 0.92420 0.71121 0.24939 1.88479 0.69385 0.32615 0.10012 1.12012 4.809 53.44
11 HS 和声搜索 0.86509 0.68782 0.32527 1.87818 0.99999 0.68002 0.09590 1.77592 0.62000 0.42267 0.05458 1.09725 4.751 52.79
12 SSG 树苗播种和生长 0.77839 0.64925 0.39543 1.82308 0.85973 0.62467 0.17429 1.65869 0.64667 0.44133 0.10598 1.19398 4.676 51.95
13 (PO)ES (PO) 进化策略 0.79025 0.62647 0.42935 1.84606 0.87616 0.60943 0.19591 1.68151 0.59000 0.37933 0.11322 1.08255 4.610 51.22
14 BSO 头脑风暴优化 0.93736 0.57616 0.29688 1.81041 0.93131 0.55866 0.23537 1.72534 0.55231 0.29077 0.11914 0.96222 4.498 49.98
15 WOAm 鲸鱼优化算法M 0.84521 0.56298 0.26263 1.67081 0.93100 0.52278 0.16365 1.61743 0.66308 0.41138 0.11357 1.18803 4.476 49.74
16 ACOm 蚁群优化 M 0.88190 0.66127 0.30377 1.84693 0.85873 0.58680 0.15051 1.59604 0.59667 0.37333 0.02472 0.99472 4.438 49.31
17 BFO-GA 细菌觅食优化 - ga 0.89150 0.55111 0.31529 1.75790 0.96982 0.39612 0.06305 1.42899 0.72667 0.27500 0.03525 1.03692 4.224 46.93
18 MEC 思维进化计算 0.69533 0.53376 0.32661 1.55569 0.72464 0.33036 0.07198 1.12698 0.52500 0.22000 0.04198 0.78698 3.470 38.55
19 IWO 入侵杂草优化 0.72679 0.52256 0.33123 1.58058 0.70756 0.33955 0.07484 1.12196 0.42333 0.23067 0.04617 0.70017 3.403 37.81
20 Micro-AIS 微型人工免疫系统 0.79547 0.51922 0.30861 1.62330 0.72956 0.36879 0.09398 1.19233 0.37667 0.15867 0.02802 0.56335 3.379 37.54
21 COAm 布谷鸟优化算法 M 0.75820 0.48652 0.31369 1.55841 0.74054 0.28051 0.05599 1.07704 0.50500 0.17467 0.03380 0.71347 3.349 37.21
22 SDOm 螺旋动力学优化 M 0.74601 0.44623 0.29687 1.48912 0.70204 0.34678 0.10944 1.15826 0.42833 0.16767 0.03663 0.63263 3.280 36.44
23 NMm Nelder-Mead方法 M 0.73807 0.50598 0.31342 1.55747 0.63674 0.28302 0.08221 1.00197 0.44667 0.18667 0.04028 0.67362 3.233 35.92
24 FAm 萤火虫算法 M 0.58634 0.47228 0.32276 1.38138 0.68467 0.37439 0.10908 1.16814 0.28667 0.16467 0.04722 0.49855 3.048 33.87
25 GSA 引力搜索算法 0.64757 0.49197 0.30062 1.44016 0.53962 0.36353 0.09945 1.00260 0.32667 0.12200 0.01917 0.46783 2.911 32.34
26 BFO 细菌觅食优化 0.61171 0.43270 0.31318 1.35759 0.54410 0.21511 0.05676 0.81597 0.42167 0.13800 0.03195 0.59162 2.765 30.72
27 ABC 人工蜂群 0.63377 0.42402 0.30892 1.36671 0.55103 0.21874 0.05623 0.82600 0.34000 0.14200 0.03102 0.51302 2.706 30.06
28 BA 蝙蝠算法 0.59761 0.45911 0.35242 1.40915 0.40321 0.19313 0.07175 0.66810 0.21000 0.10100 0.03517 0.34617 2.423 26.93
29 SA 模拟退火 0.55787 0.42177 0.31549 1.29513 0.34998 0.15259 0.05023 0.55280 0.31167 0.10033 0.02883 0.44083 2.289 25.43
30 IWDm 智能水滴 M 0.54501 0.37897 0.30124 1.22522 0.46104 0.14704 0.04369 0.65177 0.25833 0.09700 0.02308 0.37842 2.255 25.06
31 PSO 粒子群优化 0.59726 0.36923 0.29928 1.26577 0.37237 0.16324 0.07010 0.60572 0.25667 0.08000 0.02157 0.35823 2.230 24.77
32 Boids算法 虚拟生物算法 0.43340 0.30581 0.25425 0.99346 0.35718 0.20160 0.15708 0.71586 0.27846 0.14277 0.09834 0.51957 2.229 24.77
33 MA 猴群算法 0.59107 0.42681 0.31816 1.33604 0.31138 0.14069 0.06612 0.51819 0.22833 0.08567 0.02790 0.34190 2.196 24.40
34 SFL 混合蛙跳算法 0.53925 0.35816 0.29809 1.19551 0.37141 0.11427 0.04051 0.52618 0.27167 0.08667 0.02402 0.38235 2.104 23.38
35 FSS 鱼群搜索 0.55669 0.39992 0.31172 1.26833 0.31009 0.11889 0.04569 0.47467 0.21167 0.07633 0.02488 0.31288 2.056 22.84
36 RND 随机 0.52033 0.36068 0.30133 1.18234 0.31335 0.11787 0.04354 0.47476 0.25333 0.07933 0.02382 0.35648 2.014 22.37
37 GWO 灰狼优化算法 0.59169 0.36561 0.29595 1.25326 0.24499 0.09047 0.03612 0.37158 0.27667 0.08567 0.02170 0.38403 2.009 22.32
38 CSS 人工电场算法 0.44252 0.35454 0.35201 1.14907 0.24140 0.11345 0.06814 0.42299 0.18333 0.06300 0.02322 0.26955 1.842 20.46
39 EM 类电磁算法 0.46250 0.34594 0.32285 1.13129 0.21245 0.09783 0.10057 0.41085 0.15667 0.06033 0.02712 0.24412 1.786 19.85


总结

二进制遗传算法(BGA)在构建CLA的思路时起到了一定的作用。我的目标是开发一个速度更快的算法。因此,我提出了用十进制编码替换二进制编码的想法。代码锁机制成为了创建该算法的原型。事实证明,这是一个成功的解决方案。CLA的运行速度比BGA快,同时在效率方面也能成功与之竞争。此外,十进制编码在生成数字组合时允许使用不同类型的分布,这对于某些任务可能是有用的(在代码中,幂律分布和正态分布均已被注释掉,如有需要可以使用)。实验表明,在这种情况下,使用简单的均匀分布反而更为有效。

综上所述,CLA组合锁算法在所有测试函数上都表现出了卓越的性能、稳定性和效率。这表明该算法具有优秀的可扩展性,能够应对复杂问题,同时也凸显了CLA在各种优化场景中的灵活性和广阔的前景。”

标签

图例2. 根据相关测试,将算法的颜色等级大于或等于0.99的结果以白色突出显示。

图表

图例 3. 算法测试结果的直方图(标尺从 0 到 100,数字越大结果越好,

其中 100 是理论上的最大可能结果,将计算评级表格的脚本存档)


CLA的优缺点:

优势:

  1. 在各种类型的功能上表现出色。
  2. 实现简单。

缺点:

  1. 低维函数结果分散。

文章附有一个包含当前版本算法代码的归档文件。本文作者对标准算法描述的绝对准确性不承担责任。为提升搜索能力,已经对其中的许多算法进行了修改。文章中表述的结论和论断都是基于实验的结果。

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/14878

附加的文件 |
CLA.zip (25.42 KB)
理解编程范式(第 2 部分):面向对象方式开发价格行为智能系统 理解编程范式(第 2 部分):面向对象方式开发价格行为智能系统
学习面向对象的编程范式,及其在 MQL5 代码中的应用。这是第二篇文章,更深入地讲解面向对象编程的规范,并通过一个实际示例提供上手经验。您将学习如何运用 EMA 指标,和烛条价格数据,将我们早期开发的过程化价格行为智能系统转换为面向对象的代码。
重构经典策略:原油 重构经典策略:原油
在本文中,我们重新审视一种经典的原油交易策略,旨在通过利用监督机器学习算法来对其进行优化。我们将构建一个最小二乘模型,该模型基于布伦特原油(Brent)和西德克萨斯中质原油(WTI)之间的价差来预测未来布伦特原油价格。我们的目标是找到一个能够预测布伦特原油未来价格变化的领先指标。
改编版 MQL5 网格对冲 EA(第 III 部分):优化简单对冲策略(I) 改编版 MQL5 网格对冲 EA(第 III 部分):优化简单对冲策略(I)
在第三部分中,我们重新审视了早前开发的简单对冲和简单网格智能系统(EA)。我们的重点转移到通过数学分析和蛮力方式完善简单对冲 EA,旨在实现最优策略用法。本文深入探讨了该策略的数学优化,为在日后文章中探索未来基于编码的优化奠定了基础。
为 MetaTrader 5 开发 MQTT 客户端:TDD 方法 - 最终篇 为 MetaTrader 5 开发 MQTT 客户端:TDD 方法 - 最终篇
本文是介绍我们针对 MQTT 5.0 协议的本机 MQL5 客户端的开发步骤系列文章的最后一部分。尽管该库尚未投入实际使用,但在此部分中,我们将使用我们的客户端来更新来自另一个经纪商的报价(或利率)的自定义交易品种。请参阅本文底部以获取有关该库的当前状态的更多信息、它与 MQTT 5.0 协议完全兼容所缺少的内容、可能的路线图以及如何关注和促进其发展。