Discussing the article: "Population optimization algorithms: Shuffled Frog-Leaping algorithm (SFL)"

 

Check out the new article: Population optimization algorithms: Shuffled Frog-Leaping algorithm (SFL).

The article presents a detailed description of the shuffled frog-leaping (SFL) algorithm and its capabilities in solving optimization problems. The SFL algorithm is inspired by the behavior of frogs in their natural environment and offers a new approach to function optimization. The SFL algorithm is an efficient and flexible tool capable of processing a variety of data types and achieving optimal solutions.

The Shuffled Frog Leaping Algorithm (SFL) was proposed by М. Eusuff and other authors in 2003. This algorithm combines the principles of the memetic algorithm and the particle swarm algorithm, and its design was inspired by the behavior of a group of frogs during the foraging process.

The SFL algorithm was originally developed as a metaheuristic method for solving combinatorial optimization problems. It is based on the use of mathematical functions and informed heuristic search.

The SFL algorithm consists of several interacting virtual populations of frogs called memeplexes. Virtual frogs act as hosts or carriers of memes, where a meme represents a unit of cultural evolution. Each memeplex undergoes an independent local search using a method similar to particle swarm optimization, but with an emphasis on local search.

To support global exploration, virtual frogs are periodically shuffled and reorganized into new memeplexes using a method similar to the shuffled complex evolution algorithm. In addition, random virtual frogs are generated and replaced in the population to allow improved information to be generated randomly.

The shuffled frog-leaping is an effective method for solving complex optimization problems. It can achieve optimal solutions in various application domains. In this article, we will look at the basic principles and applications of this algorithm, as well as its advantages and limitations.

Author: Andrey Dik

 
К каждой статье я прикрепляю архив, содержащий обновленные актуальные версии кодов алгоритмов, описанных в предыдущих статьях.

Thanks to the author for doing a great job and for the gratuitous opportunity to use it!


enum EFunc
{
  Skin,
  Forest,
  Megacity,
  Rastrigin,
  Universe
};
C_Function *SelectFunction (EFunc f)
{
  C_Function *func;
  switch (f)
  {
    case  Skin:
      func = new C_Skin (); return (GetPointer (func));
    case  Forest:
      func = new C_Forest (); return (GetPointer (func));
    case  Megacity:
      func = new C_Megacity (); return (GetPointer (func));
    case  Rastrigin:
      func = new C_Rastrigin (); return (GetPointer (func));
    case  Universe:
      func = new C_Universe (); return (GetPointer (func));
    
    default:
      func = new C_Skin (); return (GetPointer (func));
  }
}

I'm looking at the code a bit. And replaced this beauty with such a horror.

#property script_show_inputs

#include <Math\Functions.mqh> // https://www.mql5.com/en/articles/13366

template <typename T>
C_Function* New( const string &ClassName ) { return((typename(T) == ClassName) ? new T : NULL); }

C_Function* New2( string ClassName )
{  
  typedef C_Function* (*TNew)( const string& );
  static const TNew FuncNew[] = {New<C_Skin>, New<C_Forest>, New<C_Megacity>, New<C_Rastrigin>, New<C_Universe>};

  C_Function* Res = NULL;
  
  ClassName = "class " + ClassName;
  
  for (uint i = ArraySize(FuncNew); (Res == NULL) && (bool)i--;)
    Res = FuncNew[i](ClassName);  
    
  return(Res);
}

C_Function* SelectFunction2( const EFunc f )
{
  return(New2("C_" + EnumToString(f)));
}

input EFunc inFunc = Skin;

void OnStart()
{
  C_Function* Func = SelectFunction2(inFunc);
  
  if (Func != NULL)
  {
    Print(Func.GetNamFun());
    
    delete Func;
  }
}
 
fxsaber #:

Looking at the code a little bit.

If I understand correctly, all implementations of optimisation algorithms in the form of classes have some unformatted common interface. In particular, setting the search cloud.

  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search

Is it possible to formalise it in the form of some easy-to-use variant? Roughly speaking, there is a base class, we inherit implementations of all algorithms from it, and then use them in the same way through virtual functions.

 
fxsaber #:

Thanks to the author for doing a great job and for the gratuitous opportunity to use it!

Thanks, glad my work is useful)))

fxsaber #:

Looking at the code a bit. And replaced this beauty with such a horror.

interesting

fxsaber #:

If I understand correctly, all implementations of optimisation algorithms as classes have some kind of unformatted common interface. Specifically, the search cloud specification.

Is it possible to formalise it in some easy-to-use variant? Roughly speaking, there is a base class, we inherit implementations of all algorithms from it, and then use them in the same way through virtual functions.

1. yes, I took the simple way and made the boundary conditions of algorithms in the form of open members - arrays.

2. in general, while there is a huge variety of optimisation algorithms in terms of the logic of their work, I tried to make them all uniform, they all have three steps: initialisation, moving agents to new positions and revision, and between the last two, calculation of FF, this allows flexible application of algorithms in user applications.

3. i had the idea to make all algorithms as child objects of a generic class, but this prevents for teaching purposes of the articles, variables are named and commented specific to each algorithm and help to understand the logic better.

4. however, it is true that all algorithms can be unified and brought to uniformity thanks to the work done in point 2.


The rangeMax and other boundary conditions should be arguments in the Init method.

 
fxsaber #:


I'm looking at the code a little bit. I replaced this beauty with such a horror.

The creation of a function on request should be done in the class itself (without string dances and "tying" on matching fragments of class names and enumeration elements). There's a variant of the author there. Here is another one - something like this:

Functions.mqh file:

class C_Function; // forward declaration for use in FunctionInstance base class

class FunctionInstance // common parent for all fabrics to be used in unified manner, for example listed in an array
{
  protected:
    C_Function *instance;
  public:
    FunctionInstance(): instance(NULL) { }
    ~FunctionInstance()                    // destructor provides garbage collection
    {
      if(CheckPointer(instance) == POINTER_DYNAMIC) delete instance;
    }
    virtual C_Function *create() = 0;
};

template<typename T>
class FunctionFabric: public FunctionInstance // specific fabric
{
  public:
    virtual T *create() override
    {
      if(instance == NULL) instance = new T; // here dynamic "singleton" pattern is implemeted for simplicity only (could be a collection of objects or no references at all)
      return instance;
    }
};

//------------------------------------------------------------------------------
class C_Function
{
  public:
  template<typename T>
  static FunctionFabric<T> *fabric()
  {
    static FunctionFabric<T> singleton; // here static "singleton" is implemeted as most appropriate for fabric (no need to have more than 1 fabric per class)
    return &singleton;
  }
  ...
};
...

Use in a script like this:

C_Function* NewX(const EFunc elem)
{
  // order of initialization corresponds to EFunc enumeration
  static FunctionInstance *pointers[] = {C_Function::fabric<C_Skin>(), C_Function::fabric<C_Forest>(), C_Function::fabric<C_Megacity>(), C_Function::fabric<C_Rastrigin>(), C_Function::fabric<C_Universe>()};
  return pointers[elem].create();
}

void OnStart()
{
  C_Function* Func = NewX(inFunc);
  
  if (Func != NULL)
  {
    Print(Func.GetNamFun());
    
    // delete Func; // not needed anymore, fabric will do itself
  }
}
 
Stanislav Korotky #:

By all means, creating a function on request should be in the class itself (without string dances and "tying" on matching fragments of class names and enumeration elements). There's a variant of the author there. Here is another one - something like this:

Functions.mqh file:

Use in a script like this:

Two arguments against this option.

  1. Refuse to specify a function by a string - refuse to specify robot settings via ini-file.
  2. Singleton - refusal of parallel work of several identical robots with different settings.
 
fxsaber #:

Two arguments against this option.

  1. Refusal to specify a function by a string - refusal to specify robot settings via an ini-file.
  2. Singleton - refusal of parallel work of several identical robots with different settings.

I sketched it just because if I'm going to create some contrivances, then without potential problems - I was "hooked" by the use of loop with string search (!) - it can be super inefficient in bigger programmes.

Not only string parameters in the ini file, but also other types (though represented by text).

Singleton at a factory is fine. Singleton at function object - in this case just for the operability of the example - you can implement multiplicity.

 
Stanislav Korotky #:

I just sketched it out because if I'm going to build some contrivances, it should be without potential problems - I was "hooked" by the use of a loop with string search (!) - it can be super inefficient in bigger programmes.

The ini-file does not only contain string parameters, but also other types of parameters (although they are represented by text).

A singleton at a factory is fine. Singleton at function object - in this case just for the operability of the example - you can implement multiplicity.

I use string-resolution at the initialisation stage. I think it takes less than a millisecond. Honestly, I didn't feel any potential problems.

 
fxsaber #:

Thanks to the author for doing a great job and for the gratuitous opportunity to use it!



I'm looking at the code a bit. And replaced this beauty with such a horror.

What's the gain? It's really horrible. Sorry, if anything)))

 
Stanislav Korotky #:

By all means, creating a function on request should be in the class itself (without string dances and "tying" on matching fragments of class names and enumeration elements). There's a variant of the author there. Here is another one - something like this:

Functions.mqh file:

Use in a script like this:

Sorry, but I'm wrong of course, right there in that line of code:

static FunctionInstance *pointers[] = {C_Function::fabric<C_Skin>(), C_Function::fabric<C_Forest>(), C_Function::fabric<C_Megacity>(), C_Function::fabric<C_Rastrigin>(), C_Function::fabric<C_Universe>()};
 

will not create an object of each type?

...then how, only one type will be used during the whole time of the programme.

 
Dmitry Fedoseev #:

What's the gain? I mean, it's really awful. I apologise, if anything)))

That's a tough question. I don't know.