function [globDB,realfobj_count] = dynDB_managem_v4_A(mode,globDB,DBmaxsz,pop_size,fobj,updPos,real_fitness,merit_order,improv_counter,iter)
% This function performs the management of the dynamic database that is used (contains the data) to build the surrogate model
%_______________________________________________________________________________________________________________________________%
% The DB has a maximum size of DBsize, from which upon a particle must be removed
% globDB is a struct variable that contains:
% globDB.Pos: Positions (i.e. the agents that are deemed noteworthy to build the surrogate) that constitute the input train data
% globDB.Fit: Real fitness of the stored positions/agents, that constitute the target train data
% globDB.Age: variable that tells the iteration number in which a certain stored position has entered the DB
% globDB.DBentry_countR1, globDB.DBentry_countR2, globDB.DBentry_countR3, globDB.DBentry_countR4:
%         .... variables that counts how many times this specific rule (condition) are used to introduce particles into the DB
% realfobj_count: returns how many times this function has employed the real objective function to update the
%         ....assistedMetaheuristic counter of this parameter (stop criterion)
%_______________________________________________________________________________________________________________________________%
% $$ Input Variables
% 1) globDB -> old global Database data
% 2) DBmaxsz -> Maximum DB length (allowable number of stored positions and its accompanying variables)
% 3) pop_size -> population/swarm size
% 4) fobj -> real objective function
% 5) updPos -> the latest/updated positions from the metaheuristic, which are not all accepted
%         .... (as we saw if there is no improvement in the surrogate value in comparison with its
%         .... predecessor pre-updated position, # i.e. surrogatevalue(Pos[iter+1])>real_fitness(Pos[iter+1]# ) 
%         .... and are therefore the 'updPos' variable is only temporary, but is used to compute the 'merit_order'   
% 6) real_fitness -> (real) fitness of the accepted swarm/positions, to store in the DB if the position
%         .... is deemed as worthy
% 7) merit_order -> sorted order of the most fit candidate updated positions, according to the 
%         .... dual based merit metric (ranked order of the pop_size 'updPos'
% 8) improv_counter -> vector with a counter for each pop_size updated position, 'updPos'
%         .... that tells us if non-null tells that this temporary position was accepted 
%         .... and a real fitness was calculated, # i.e. surrogatevalue(Pos[iter+1])<=real_fitness(Pos[iter+1]#
%         .... when null it means the ith positions did not show an improved surrogate value, 
%         .... i.e., not accepted yet as a valid candidate, so no real fitness is known 
% 9) iter -> current iteration (iter+1) which will be used as the 'globDB.Age' information
%_______________________________________________________________________________________________________________________________%
switch mode
    case 'init' % Initializes the global DB with only the Initial Positioning from the Metaheuristic
        %_______________________________________________________________________________________________________________________________%
        globDB=struct('Pos',updPos,'Fit',real_fitness,'Age',iter.*zeros(pop_size,1),...
            'DBentry_countR1',0,...
            'DBentry_countR2',0,...
            'DBentry_countR3',0,...
            'DBentry_countR4',0);
        realfobj_count=[];
        %_______________________________________________________________________________________________________________________________%
    case 'update'
        %_______________________________________________________________________________________________________________________________%
        %% (Potentially) update the DB with new candidates, i.e., updated positions
        % ____  Semi-Elitista, 4 rules até às 25% melhores -> v4
        % ____ without age consideration for the dynamic DB decision to enter and remove position from the DB -> vA
        tresh_fmerit=[0.15,0.15,0.25,0.25];
        realfobj_count=0;
        for i=1:pop_size % for all/each of the search agents
            %-------------------------------------------------------------------------%
            %_Conditions Global database update:
            %-------------------------------------------------------------------------%
            % _> Prelim Rule/Condition 0: Only evaluates positions different to the ones already stored in the DB (in theory mostly ensured by the fmerit metric)
            if (sum(ismember(globDB.Pos,updPos(i,:),'rows'))==0) % if this sum is 0 it means the potential position to add to 
            %  i.e., ismember returns a vector of zeros)
            %_______________________________________________________________________%
                % _> Rule/Condition 1: se o agente dos 'updPos' tiver nas 15% com menor fmerit (melhores em termos de fmerit)
                % and besides if the  condition improv_counter(i) improv_counter(i)~=0 ou ==1, i.e.,
                % the fitness was evaluated usimng the fobj real: f_aprox(i)<Pbest(i), which is already stored in 'real_fitness'
                if (~isempty(find(merit_order(1:ceil(tresh_fmerit(1)*pop_size))==i,1)) && (improv_counter(i)))  
                    globDB.Pos(end+1,:)=updPos(i,:);
                    globDB.Fit(end+1)=real_fitness(i);
                    globDB.Age(end+1)=iter;
                    globDB.DBentry_countR1=globDB.DBentry_countR1+1;
                %_______________________________________________________________________%
                % _> Rule/Condition 2: se o agente dos 'updPos' tiver nas 15% com menor fmerit (melhores em termos de fmerit)
                % and besides but with the  condition ~improv_counter(i) improv_counter(i)==0 , i.e.,
                % the fitness of this position is not yet available., since  f_aprox(i)>Pbest(i)
                elseif (~isempty(find(merit_order(1:ceil(tresh_fmerit(2)*pop_size))==i,1)) && (~improv_counter(i)))  
                    globDB.Pos(end+1,:)=updPos(i,:);
                    globDB.Fit(end+1)=feval(fobj,updPos(i,:)); % in this case we have to still compute its real fitness since 
                    %         .... it was not available (in the main assistedMetaheuristic function it was not deemed as promising)
                    globDB.Age(end+1)=iter;
                    globDB.DBentry_countR2=globDB.DBentry_countR2+1;
                    realfobj_count=realfobj_count+1; %this function has employed the real fobj, so needs to return this info to 
                    %         ....the main assistedMetaheuristic function
                %_______________________________________________________________________%
                % _> Rule/Condition 3: se o agente dos 'updPos' tiver entre os 15% e 25% com menor fmerit
                % and besides if the  condition improv_counter(i) improv_counter(i)~=0 ou ==1, i.e.,
                % the fitness was evaluated usimng the fobj real: f_aprox(i)<Pbest(i), 
                % which is already stored in 'real_fitness', but only 25% of the times random>0.75
                elseif (~isempty(find(merit_order(ceil(tresh_fmerit(3-1)*pop_size)+1:ceil(tresh_fmerit(3)*pop_size))==i,1)) ...
                        && (improv_counter(i)) && (rand>0.75))  
                    globDB.Pos(end+1,:)=updPos(i,:);
                    globDB.Fit(end+1)=real_fitness(i);
                    globDB.Age(end+1)=iter;
                    globDB.DBentry_countR3=globDB.DBentry_countR3+1;
                %_______________________________________________________________________%
                % _> Rule/Condition 4: se o agente dos 'updPos' tiver entre os 15% e 25% com menor fmerit
                % and besides but with the  condition ~improv_counter(i) improv_counter(i)==0 , i.e.,
                % the fitness of this position is not yet available., since
                % f_aprox(i)>Pbest(i), but only 25% of the times random>0.75
                elseif (~isempty(find(merit_order(ceil(tresh_fmerit(3-1)*pop_size)+1:ceil(tresh_fmerit(4)*pop_size))==i,1)) ...
                        && (~improv_counter(i)) && (rand>0.75))  
                    globDB.Pos(end+1,:)=updPos(i,:);
                    globDB.Fit(end+1)=feval(fobj,updPos(i,:)); % in this case we have to still compute its real fitness since 
                    %         .... it was not available (in the main assistedMetaheuristic function it was not deemed as promising)
                    globDB.Age(end+1)=iter;
                    globDB.DBentry_countR4=globDB.DBentry_countR4+1;
                    realfobj_count=realfobj_count+1; %this function has employed the real fobj, so needs to return this info to 
                    %         ....the main assistedMetaheuristic function
                end
                %_______________________________________________________________________%
            end
            %_______________________________________________________________________%
        end
        %_______________________________________________________________________________________________________________________________%
        %% Check if the DB maximum length has not been exceeded
        % ____ If so remove solely based on the ranked fitness of the stored positions -> vA
        if (length(globDB.Fit)>DBmaxsz) % if there are more positions stored than the allowed number
            [fit_sorted,idx_sorted]=sort(globDB.Fit,'ascend'); %sort the best positions in terms of real fitness
            globDB.Fit=fit_sorted(1:DBmaxsz); %select only the 'DBmaxsz' best positions
            globDB.Pos=globDB.Pos(idx_sorted(1:DBmaxsz),:);
            globDB.Age=globDB.Age(idx_sorted(1:DBmaxsz),1);
        else
            [globDB.Fit,idx_sorted]=sort(globDB.Fit,'ascend'); %sort the best positions in terms of real fitness
            globDB.Pos=globDB.Pos(idx_sorted,:);
            globDB.Age=globDB.Age(idx_sorted,1);            
        end
        %_______________________________________________________________________________________________________________________________%
end
%_______________________________________________________________________________________________________________________________%
end
%_______________________________________________________________________________________________________________________________%
% % by Pedro Bento November 2023
% When using please cite and refer this code and its author!