USE(7.2)
USE(7.2)
AbEC - Adding a New Component
<< >>
< [ Home ] < 1. [ Use ] > 2. [ Configuration files ] > 3. [ Fitness function ] > 4. [ Running ] > 5. [ Results ] > 6. [ Example ] > 7. [ Adding new components ] >> 7.1. [ Adding a New Optimizer ] >>>> 7.1.1. [ Example of a New Optimizer ] >> 7.2. [ Adding a New Component ] >>>> 7.2.1. [ Example of a New Component ] >> 7.3. [ Adding a New Metric File ] >>>> 7.3.1. [ Example of a New Metric ]

> AbEC/abec/components/component.py

This is the file where we are going to implement the component. First of all, lets talk about some requirements.

> Hyper-parameters

In order to set the hyper-parameters of the component, inside of the file it is necessary to be defined one list, named params, where each element of this list we put the hyper-parameters of our new component. Below a generic example of this list.

params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]






> Scope

Once we have defined the name of our component (the name of the file), and the hyper-parameters, the following fair doubt may arise: "But not all components act in the same way in the algorithm, what should I do?".
Well, for the optimizers this is not a problem but, to deal with it for the general components, the algorithm is divided into 5 scopes, and a list is used to indicate which scope the component should be. The scopes are:
  • Initialization (INI): These are the components that act on the initialization of the algorithms, before enter in the optimization loop (e.g Multipopulation with fixed number); In practice, this type of component receives as parameters a list containing all the subpopulations and the dictionary parameters which contains all the configurations of the configurations files. And should return the list of the subpopulations.

    params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]
    scope = ["INI"]

    def component(pop, runVars, parameters):
        .
        .
        .
        return pop, runVars


    The template of a new (INI) component can be downloaded in the link: [ Component template ].




  • Global Diversity (GDV): These are the components that acts on the whole population in order to increase the diversity. This means, if you have for example more than one subpopulation, and the component deal with all of them, this is the scope. In practice this type of component receive as parameter a list containing all the subpopulations, the dictionary parameters which contains all the configurations of the configurations files and a list called "randomInit", this list is used to know which of the subpopulations need to be reinitialized based on the ID of the subpopulation. This means, each position of this list is refered to the correspondent subpopulation id, for example, if the index 5 of the list is set up to 1, this means that the subpopulation with ID = 5 need to be reinitialized. So, After apply the component, it needs to return the "randomInit" list.

    params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]
    scope = ["GDV"]

    def component(pop, runVars, parameters, randomInit):
        .
        .
        .
        return randomInit, runVars


    The template of a new (GDV) component can be downloaded in the link: [ Component template ].




  • Global Exploration (GER): These are the components that acts in all the populations (in case of multipopulations) in order to modify them. In practice this type of component receive as parameter a list containing all the subpopulations and the dictionary parameters which contains all the configurations of the configurations files. So, after apply the component, it needs to return the list of the subpopulations.

    params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]
    scope = ["GER"]

    def component(pop, runVars, parameters):
        .
        .
        .
        return pop, runVars


    The template of a new (GER) component can be downloaded in the link: [ Component template ].




  • Global Exploitation (GET): These are the components that acts in the global best of all populations (in case of multipopulations). In practice this type of component receive as parameters the global best and the dictionary parameters which contains all the configurations of the configurations files. So, after apply the component, it needs to return the global best.

    params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]
    scope = ["GET"]

    def component(best, runVars, parameters):
        .
        .
        .
        return best, runVars


    The template of a new (GET) component can be downloaded in the link: [ Component template ].




  • Local Diversity (LDV): These are the components that acts in each subpopulation (in case of multipopulation) and modify them. In practice this type of component receive as parameters the subpopulation and the dictionary parameters which contains all the configurations of the configurations files. So, after apply the component, it needs to return the subpopulation.

    params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]
    scope = ["LDV"]

    def component(subpop, runVars, parameters):
        .
        .
        .
        return subpop, runVars


    The template of a new (LDV) component can be downloaded in the link: [ Component template ].
With the hyper-parameters defined, There are two methods that are mandatory, they are cp and component.




> Confirmation of hyper-parameters (cp)

This method is used to confirm that all the values of the hyper-parameters are within the allowed range. A generic example of this method is showed below:

from aux.aux import errorWarning
import sys

def cp(parameters):
    if not (MIN <= parameters["<NAME-OF-COMPONENT>_<HYPER-PARAMETER-1>"] <= MAX):
       errorWarning("3.X.1", "algoConfig.ini", "<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-1>", "The <HYPER-PARAMETER-1> should be in the interval [MIN, MAX]")
       sys.exit()

    if not (MIN <= parameters["<NAME-OF-COMPONENT>_<HYPER-PARAMETER-2>"] <= MAX):
       errorWarning("3.X.2", "algoConfig.ini", "<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-2>", "The <HYPER-PARAMETER-2> should be in the interval [MIN, MAX]")
       sys.exit()

    if not (MIN <= parameters["<NAME-OF-COMPONENT>_<HYPER-PARAMETER-N>"] <= MAX):
       errorWarning("3.X.N", "algoConfig.ini", "<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-N>", "The <HYPER-PARAMETER-N> should be in the interval [MIN, MAX]")
       sys.exit()

    return 1





> component.py

And then the complete file will be something like:

from aux.aux import errorWarning
import sys

params = ["HYPER-PARAMETER-1", "HYPER-PARAMETER-2", ..., "HYPER-PARAMETER-N"]
scope = ["XXX"]

def cp(parameters):
    if not (MIN <= parameters["<NAME-OF-COMPONENT>_<HYPER-PARAMETER-1>"] <= MAX):
       errorWarning("3.X.1", "algoConfig.ini", "<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-1>", "The <HYPER-PARAMETER-1> should be in the interval [MIN, MAX]")
       sys.exit()

    if not (MIN <= parameters["<NAME-OF-COMPONENT>_<HYPER-PARAMETER-2>"] <= MAX):
       errorWarning("3.X.2", "algoConfig.ini", "<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-2>", "The <HYPER-PARAMETER-2> should be in the interval [MIN, MAX]")
       sys.exit()

    if not (MIN <= parameters["<NAME-OF-COMPONENT>_<HYPER-PARAMETER-N>"] <= MAX):
       errorWarning("3.X.N", "algoConfig.ini", "<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-N>", "The <HYPER-PARAMETER-N> should be in the interval [MIN, MAX]")
       sys.exit()

    return 1

def component(depends on the scope, runVars, parameters):
    .
    .
    .
    return depends on the scope





> algoConfig.ini

Once you have added the component script in the respective folder, you will be able to configure this component in the configuration file "algoConfig.ini". The component will appers in the file as follows:


{
"COMP_<NAME-OF-THE-COMPONENT>": 1 -> 0 or 1; 0 for turned off and 1 for turned on (bool)
}

The component parameters:

{
"COMP_<NAME-OF-THE-COMPONENT>": 1, -> 0 or 1; 0 for turned off and 1 for turned on (bool)
"COMP_<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-1>": value, -> range permitted for the value (type)
"COMP_<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-2>": value, -> range permitted for the value (type)
.
.
"COMP_<NAME-OF-THE-COMPONENT>_<HYPER-PARAMETER-N>": value -> range permitted for the value (type)
}

[~]$ Example of a new Component
As an example, we are going now to add an component, the Local Search (LS).

> AbEC/abec/components/local_search.py


$ nano abec/components/local_search.py


> [ file ]

import sys
import copy
import abec
import aux.globalVar as globalVar
from aux.aux import errorWarning

params = ["ETRY", "RLS"]
scope = ["GET"]

def cp(parameters):
    if not (0 < parameters["COMP_LOCAL_SEARCH_ETRY"] < parameters["POPSIZE"]):
       errorWarning("4.4.1", "algoConfig.ini", "COMP_LOCAL_SEARCH_ETRY", "The number of tries of the Local Search should be 0 between [1, POPSIZE[")
       sys.exit()

    if not (0 < parameters["COMP_LOCAL_SEARCH_RLS"] < parameters["MAX_POS"]):
       errorWarning("3.4.2", "algoConfig.ini", "COMP_LOCAL_SEARCH_RLS", "The Local Search radio should be 0 between ]0, MAX_POS[")
       sys.exit()

    return 1

def component(best, runvars, parameters):
    bp = copy.deepcopy(best)
    for _ in range(parameters["COMP_LOCAL_SEARCH_ETRY"]):
       for i in range(parameters["NDIM"]):
          bp["pos"][i] = bp["pos"][i] + globalVar.rng.uniform(-1, 1)*parameters["COMP_LOCAL_SEARCH_RLS"]
       bp["fit"] = abec.evaluate(bp, parameters, be = 1)
       if bp["fit"] < best["fit"]:
          best = copy.deepcopy(bp)

    return best, runVars



And then to use it in the algorithm, we set it up in the configuration file algoConfig.ini, just like this:

$ nano abec/algoConfig.ini


> [ file ]

{
"ALGORITHM": "DE_LS",
"POPSIZE": 50,
"MIN_POS": -10,
"MAX_POS": 10,
"DE_POP_PERC": 1,
"DE_F": 0.5,
"DE_CR": 0.7,
"COMP_LOCAL_SEARCH": 1,
"COMP_LOCAL_SEARCH_ETRY": 10,
"COMP_LOCAL_SEARCH_RLS": 1
}

Be free to use this framework.
AbEC © 2023.