A brief introduction of jellyfish search optimization algorithm

This study developed a new meta-heuristic algorithm inspired by the behavior of jellyfish in the ocean, known as the Artificial Jellyfish Search (JS) Optimizer. Simulations of jellyfish searching behavior included their following ocean currents, their movement through a swarm (active and passive), time-control mechanisms that switched between these movements, and converging to a jellyfish flower state. The new algorithm has been successfully tested on the benchmark function and optimization problems. It is worth noting that JS has only two control parameters, namely population size and iteration number. As a result, JS is very simple to use and can be an excellent metaheuristic algorithm for solving optimization problems.

Two, some source code

%% Main MOJS optimizer
function ARCH = MOJS(params,MultiObj)
% Parameters
Np      = params.Np;
Nr      = params.Nr;
MaxIt   = params.maxiter;
ngrid   = params.ngrid;
fun     = MultiObj.fun;
nVar    = MultiObj.nVar;
var_min = MultiObj.var_min(:);
var_max = MultiObj.var_max(:);
it=1;
% Initialization by Eq. 25
POS=initialchaos(7,Np,nVar,var_max',var_min');
POS_fit      = fun(POS);
ELI_POS      = POS;
ELI_POS_fit  = POS_fit;
DOMINATED    = checkDomination(POS_fit);
ARCH.pos     = POS(~DOMINATED,:);
ARCH.pos_fit = POS_fit(~DOMINATED,:);
ARCH         = updateGrid(ARCH,ngrid);

display(['Iteration #0 - Archive size: ' num2str(size(ARCH.pos,1))); %% Main MOJS loop stopCondition =false;
while ~stopCondition
    % Select leader by Eq. 16
    h = selectLeader(ARCH);
    % Calculate time control by Eq. 15
    Ct=abs((1-it*((1)/MaxIt))*(2*rand- 1));
    if Ct>=0.5
        Meanvl=mean(ELI_POS);
        for i=1:Np
            % The new position is determined by Eq19. and Eq20.
            POS(i,:) = ELI_POS(i,:) + Levy(nVar).*(ARCH.pos(h,:) - 3*rand([1 nVar]).*Meanvl);
        end
    else
        for i=1:Np
            if rand<(1-Ct)
                % Jellyfish follow type B
                % Determine the direction by Eq. 24
                j=i;
                while j==i
                    j=randperm(Np,1);
                end
                Step = ELI_POS(i,:) - ELI_POS(j,:);
                if dominates(ELI_POS_fit(j,:),ELI_POS_fit(i,:))
                    Step = -Step;
                end
                % The new position is determined by Eq. 22
                POS(i,:) =ARCH.pos(h,:) + rand([1 nVar]).*Step;
            else
                % Jellyfish follow type A
                % The new position is determined by Eq. 21
                POS(i,:)=ARCH.pos(h,:)+Levy(nVar).*(ELI_POS(i,:)-ARCH.pos(h,:));
            end
        end
    end
    %% Update new position by opposition-based jumping using Eq. 26
    if rand <(it/MaxIt)
        [POS] = OPPOS(POS,var_max,var_min);
    end
    %% Check boundaries
    if rand>=0.5
        POS=checksimplebounds(POS,var_min',var_max');
    else
        POS = checkBoundaries(POS,var_max,var_min);
    end
    %% Evaluate the population
    POS_fit = fun(POS);
    pos_best = dominates(POS_fit, ELI_POS_fit);
    best_pos = ~dominates(ELI_POS_fit, POS_fit);
    best_pos(rand(Np,1) > =0.5) = 0;
    if(sum(pos_best)>1)
        ELI_POS_fit(pos_best,:) = POS_fit(pos_best,:);
        ELI_POS(pos_best,:) = POS(pos_best,:);
    end
    if(sum(best_pos)>1)
        ELI_POS_fit(best_pos,:) = POS_fit(best_pos,:);
        ELI_POS(best_pos,:) = POS(best_pos,:);
    end
    %% Update the archive 
    if size(ARCH.pos,1)= =1
        ARCH.pos= POS;
        ARCH.pos_fit= POS_fit;
        ARCH = updateArchive(ARCH,ELI_POS,ELI_POS_fit,ngrid);
    else
        ARCH = updateArchive(ARCH,ELI_POS,ELI_POS_fit,ngrid);
        if size(ARCH.pos,1)= =1
            ARCH.pos= ELI_POS;
            ARCH.pos_fit= ELI_POS_fit;
        end
    end
    if(size(ARCH.pos,1)>Nr)
        % Delete the worst members from archive by Eq. 18
        ARCH = deleteFromArchive(ARCH,size(ARCH.pos,1)-Nr,ngrid);
    end
    display(['Iteration #' num2str(it) ' - Archive size: ' num2str(size(ARCH.pos,1)));
    it=it+1;
    if(it>MaxIt), stopCondition = true; end
end
%% Plotting paretofront
if(size(ARCH.pos_fit,2) = =2)
    plot(ARCH.pos_fit(:,1),ARCH.pos_fit(:,2),'or'); hold on;
    grid on; xlabel('f1'); ylabel('f2');
end
if(size(ARCH.pos_fit,2) = =3)
    plot3(ARCH.pos_fit(:,1),ARCH.pos_fit(:,2),ARCH.pos_fit(:,3),'or'); hold on;
    grid on; xlabel('f1'); ylabel('f2'); zlabel('f3');
end
end

%% This function calucates the leader performance by a roulette wheel selection
% based on the quality of each hypercube
function selected = selectLeader(ARCH)
% Roulette wheel
prob    = cumsum(ARCH.quality(:,2));     % Cumulated probs
sel_hyp = ARCH.quality(find(rand(1.1)*max(prob)<=prob,1.'first'),1); % Selected hypercube
% Select the index leader as a random selection inside that hypercube
idx      = 1:1:length(ARCH.grid_idx);
selected = idx(ARCH.grid_idx==sel_hyp);
selected = selected(randi(length(selected)));
end

%% This function returns 1 if x dominates y and 0 otherwise
function d = dominates(x,y)
d = all(x<=y,2) & any(x<y,2);
end

%% This function checks the domination inside the population.
function domi_vector = checkDomination(fitness)
Np = size(fitness,1);
if Np>2
    domi_vector = zeros(Np,1);
    all_perm = nchoosek(1:Np,2);    % Possible permutations
    all_perm = [all_perm; [all_perm(:,2) all_perm(:,1)]];
    
    d = dominates(fitness(all_perm(:,1),:),fitness(all_perm(:,2), :)); dominated_particles = unique(all_perm(d==1.2));
    domi_vector(dominated_particles) = 1;
else
    domi_vector=ones(Np,1);
end
end

%% This function updates the archive given a new population 
function ARCH = updateArchive(ARCH,POS,POS_fit,ngrid)
% Domination between jellyfish
DOMINATED  = checkDomination(POS_fit);
ARCH.pos    = [ARCH.pos; POS(~DOMINATED,:)];
ARCH.pos_fit= [ARCH.pos_fit; POS_fit(~DOMINATED,:)];
% Domination between nondominated jellyfish and the last archive 
DOMINATED  = checkDomination(ARCH.pos_fit);
ARCH.pos_fit= ARCH.pos_fit(~DOMINATED,:);
ARCH.pos    = ARCH.pos(~DOMINATED,:);
% Updating the grid
ARCH        = updateGrid(ARCH,ngrid);
end

%% Function that updates the hypercube grid, the hypercube where belongs
function ARCH = updateGrid(ARCH,ngrid)
% Computing the  hypercube limitation
ndim = size(ARCH.pos_fit,2);
ARCH.hypercube_limits = zeros(ngrid+1,ndim);
for dim = 1:1:ndim
    ARCH.hypercube_limits(:,dim) = linspace(min(ARCH.pos_fit(:,dim)),max(ARCH.pos_fit(:,dim)),ngrid+1)'; end % Computing where belongs each jellyfish npar = size(ARCH.pos_fit,1); ARCH.grid_idx = zeros(npar,1); ARCH.grid_subidx = zeros(npar,ndim); for n = 1:1:npar idnames = []; for d = 1:1:ndim ARCH.grid_subidx(n,d) = find(ARCH.pos_fit(n,d)<=ARCH.hypercube_limits(:,d)'.1.'first')- 1;
        if(ARCH.grid_subidx(n,d)==0), ARCH.grid_subidx(n,d) = 1; end
        idnames = [idnames ', ' num2str(ARCH.grid_subidx(n,d))];
    end
    ARCH.grid_idx(n) = eval(['sub2ind(ngrid.*ones(1,ndim)' idnames '); ']);
end
% Quality based on the number of jellyfish in each hypercube
ARCH.quality = zeros(ngrid,2);
ids = unique(ARCH.grid_idx);
for i = 1:length(ids)
    ARCH.quality(i,1) = ids(i);                       
    ARCH.quality(i,2) = 10/sum(ARCH.grid_idx==ids(i)); 
end
end

%% This function deletes an excess of jellyfish inside the archive using crowding distances
function ARCH = deleteFromArchive(ARCH,n_extra,ngrid)
% Compute the crowding distances
crowding = zeros(size(ARCH.pos,1),1);
for m = 1:1:size(ARCH.pos_fit,2)
    [m_fit,idx] = sort(ARCH.pos_fit(:,m),'ascend');
    m_up     = [m_fit(2:end); Inf];
    m_down   = [Inf; m_fit(1:end- 1)];
    distance = (m_up-m_down)./(max(m_fit)-min(m_fit));
    [~,idx]  = sort(idx,'ascend');
    crowding = crowding + distance(idx);
end
crowding(isnan(crowding)) = Inf;
% This function deletes the extra jellyfish with the smallest crowding distances
[~,del_idx] = sort(crowding,'ascend');
del_idx = del_idx(1:n_extra); ARCH.pos(del_idx,:) = []; ARCH.pos_fit(del_idx,:) = []; ARCH = updateGrid(ARCH,ngrid); end %% This function checks the boundary of jellyfish search space function [POS] = checkBoundaries(POS,var_max,var_min)  % Useful matrices Np = size(POS,1);
MAXLIM   = repmat(var_max(:)',Np,1); MINLIM = repmat(var_min(:)',Np,1);
POS(POS>MAXLIM) = MAXLIM(POS>MAXLIM);
POS(POS<MINLIM) = MINLIM(POS<MINLIM);
end
function POS=checksimplebounds(POS,Lb,Ub)
for i=1:size(POS,1)
    ns_tmp=POS(i,:);
    I=ns_tmp<Lb;
    while sum(I)~=0
        ns_tmp(I)=Ub(I)+(ns_tmp(I)-Lb(I));
        I=ns_tmp<Lb;
    end
    J=ns_tmp>Ub;
    while sum(J)~=0
        ns_tmp(J)=Lb(J)+(ns_tmp(J)-Ub(J));
        J=ns_tmp>Ub;
    end
    POS(i,:)=ns_tmp;
end
end
Copy the code

3. Operation results

Matlab version and references

1 matlab version 2014A

[1] Yang Baoyang, YU Jizhou, Yang Shan. Intelligent Optimization Algorithm and Its MATLAB Example (2nd Edition) [M]. Publishing House of Electronics Industry, 2016. [2] ZHANG Yan, WU Shuigen. MATLAB Optimization Algorithm source code [M]. Tsinghua University Press, 2017.