NiaPy icon indicating copy to clipboard operation
NiaPy copied to clipboard

Squirrel search algorithm implementation

Open firefly-cpp opened this issue 3 years ago • 7 comments

Squirrel search algorithm publication is currently the most cited article in SWEVO.

It would be nice to have this algorithm in our collection.

Has anyone time to implement this algorithm?

firefly-cpp avatar Jul 01 '21 15:07 firefly-cpp

can you assign me on this?

altaregos avatar Nov 20 '21 21:11 altaregos

@altaregos, thanks. Yeah. Of course.

firefly-cpp avatar Nov 21 '21 09:11 firefly-cpp

I've made an attempt:

import numpy as np
from niapy.algorithms import Algorithm
from niapy.util.random import levy_flight
from niapy.task import Task


class SquirrelSearchAlgorithm(Algorithm):
    Name = ['SquirrelSearchAlgorithm', 'SSA']
    
    def __init__(self, population_size=50, food_sources=4, prob_predation=0.1, gliding_constant=1.9, scale=18, *args, **kwargs):
        super().__init__(population_size, *args, **kwargs)
        self.food_sources = food_sources
        self.prob_predation = prob_predation
        self.gliding_constant = gliding_constant
        self.scale = scale

    def set_parameters(self, population_size=50, food_sources=4, prob_predation=0.1, gliding_constant=1.9, scale=18, *args, **kwargs):
        super().set_parameters(population_size, *args, **kwargs)
        self.food_sources = food_sources
        self.prob_predation = prob_predation
        self.gliding_constant = gliding_constant
        self.scale = scale

    def get_parameters(self):
        params = super().get_parameters()
        params.update({
            'food_sources': self.food_sources,
            'prob_predation': self.prob_predation,
            'gliding_constant': self.gliding_constant,
            'scale': self.scale,
        })
        return params
    
    def gliding_distance(self):
        lift = 0.9783723933835806 / self.uniform(0.675, 1.5)
        drag = 1.630620655639301
        return 8.0 / (self.scale * drag / lift)
    
    def run_iteration(self, task, population, population_fitness, best_x, best_fitness, **params):
        indices = np.argsort(population_fitness)
        ht = indices[0]
        at = indices[1:self.food_sources]
        nt = indices[self.food_sources:]

        new_population = population.copy()

        for index in at:
            if self.random() >= self.prob_predation:
                new_population[index] += self.gliding_distance() * self.gliding_constant * (population[ht] - population[index])
                new_population[index] = task.repair(new_population[index], rng=self.rng)
            else:
                new_population[index] = self.uniform(task.lower, task.upper)
        
        nt = self.rng.permutation(nt)
        nt_1 = nt[:len(nt) // 2] # half go to acorn trees
        nt_2 = nt[len(nt) // 2:] # other half go to hickory trees
        
        for index in nt_1:
            if self.random() >= self.prob_predation:
                a = self.rng.choice(at)
                new_population[index] += self.gliding_distance() * self.gliding_constant * (population[a] - population[index])
                new_population[index] = task.repair(new_population[index], rng=self.rng)
            else:
                new_population[index] = self.uniform(task.lower, task.upper)

        for index in nt_2:
            if self.random() >= self.prob_predation:
                new_population[index] += self.gliding_distance() * self.gliding_constant * (population[ht] - population[index])
                new_population[index] = task.repair(new_population[index], rng=self.rng)
            else:
                new_population[index] = self.uniform(task.lower, task.upper)

        s_min = 1e-5 / (365 ** ((task.iters + 1) / (task.max_iters / 2.5)))
        sc = np.sqrt(np.sum((new_population[at] - new_population[ht]) ** 2))

        if sc < s_min:
            new_population[nt_1] = task.lower + levy_flight(size=(len(nt_1), task.dimension), rng=self.rng) * task.range
            new_population[nt_1] = task.repair(new_population[nt_1], rng=self.rng)

        new_fitness = np.apply_along_axis(task.eval, 1, new_population)
        best_x, best_fitness = self.get_best(new_population, new_fitness, best_x, best_fitness)
        
        return new_population, new_fitness, best_x, best_fitness, {}


if __name__ == '__main__':
    fit = []
    for i in range(30):
        task = Task('sphere', dimension=30, lower=-10, upper=10, max_iters=500)
        algo = SquirrelSearchAlgorithm()
        _, best_fitness = algo.run(task)
        fit.append(best_fitness)
    
    print(f'Best: {np.min(fit)}')
    print(f'Worst: {np.max(fit)}')
    print(f'Mean: {np.mean(fit)}')
    print(f'Std: {np.std(fit)}')

But I don't get the same results as the ones in the article. For this example (30 runs, 30-D sphere on [-10, 10], max_iters=500) i get:

Best: 7.5371836448343156e-06
Worst: 8.828262744205666e-05
Mean: 4.013667587147927e-05
Std: 2.289286326787123e-05

and in the article they got:

Best: 7.9225e-20
Worst: 5.7411e-07
Mean: 4.1689E-08
Std: 1.4356E-07

The article is extremely unclear, in my opinion. At least it was to me. It doesn't say how to choose which squirrels on normal trees go towards acorn trees and which towards the hickory tree, it just says "do it randomly". I just chose half randomly. Also, I don't know if I'm calculating the season constant correctly, because the equation is formatted weirdly and there's no real explanation of it. And then if the seasons change, I don't know which squirrels to move via levy flights.

Any ideas what I'm doing wrong? Otherwise I'd say it's best just not to include it.

zStupan avatar Mar 05 '22 11:03 zStupan

Hi How use this algorithm for optimization upl in mining Plz help me

Nehaazi avatar Mar 30 '24 09:03 Nehaazi

@zStupan, I'm confused by what you mean. Aren't the SSA results going to be different each time you run it? I haven't looked into this much, but just putting ideas out there

BrandonDuncan13 avatar Apr 03 '24 01:04 BrandonDuncan13

@BrandonDuncan13 yes the results are different each time, but I would expect that the average fitness over 30 runs would be of similar magnitude as the results in the paper.

zStupan avatar Apr 05 '24 07:04 zStupan

I mean, how to use this algorithm for optimization. I can't write its program. What should I study for this?

Nehaazi avatar Apr 05 '24 20:04 Nehaazi

@zStupan Ohh, okay, I see what you're talking about now. Yeah I agree the average fitness should be a similar magnitude. I will spend time trying to improve your code within the next few weeks but I don't have much confidence in improving it haha

BrandonDuncan13 avatar Apr 05 '24 20:04 BrandonDuncan13

@Nehazzi If you're looking to apply this optimization algorithm to a coding project, I would either look at the MatLab code that exists for SSA or look at how other optimization algorithms have been applied to coding projects. Then you can figure out how to apply the SSA code above to your coding project. Idk what you're asking but I think that's what you were looking for

BrandonDuncan13 avatar Apr 05 '24 20:04 BrandonDuncan13