├── AR_WB.m ├── CalACC.m ├── Dataset.mat ├── NODE.m ├── Optimizer ├── ABC.m ├── ACO.m ├── CMAES.m ├── CSO.m ├── DE.m ├── FEP.m ├── GA.m ├── PSO.m ├── Rand.m └── SA.m ├── README.md ├── TAI_manuscript.pdf ├── generate.m ├── generate_exp2fun.m ├── generate_exp2tree.m ├── generate_tree.m ├── generate_tree2exp.m └── main.m /AR_WB.m: -------------------------------------------------------------------------------- 1 | function [ACC,RANK] = AR_WB(type,TrainIn,TrainOut,TestIn,TestOut) 2 | % White-box algorithm recommendation method 3 | 4 | %% LSTM based classification 5 | % Tokenize the reverse Polish expression 6 | TrainIn = cellfun(@(s)num2str(s),TrainIn,'UniformOutput',false); 7 | TrainIn = tokenizedDocument(TrainIn'); 8 | TestIn = cellfun(@(s)num2str(s),TestIn,'UniformOutput',false); 9 | TestIn = tokenizedDocument(TestIn'); 10 | enc = wordEncoding(TrainIn); 11 | TrainIn = doc2sequence(enc,TrainIn,'Length',27); 12 | TestIn = doc2sequence(enc,TestIn,'Length',27); 13 | [~,TrainOut] = min(cell2mat(TrainOut'),[],2); 14 | TrainOut = categorical(TrainOut); 15 | % Train LSTM 16 | switch type 17 | case 1 18 | layers = [sequenceInputLayer(1) 19 | wordEmbeddingLayer(50,enc.NumWords) 20 | bilstmLayer(50,'OutputMode','last') 21 | fullyConnectedLayer(max(double(TrainOut))) 22 | softmaxLayer 23 | classificationLayer]; 24 | options = trainingOptions('adam','MaxEpochs',30,'GradientThreshold',1,'InitialLearnRate',0.01); 25 | net = trainNetwork(TrainIn,TrainOut,layers,options); 26 | save AR_WB net 27 | case 2 28 | load AR_WB net 29 | end 30 | 31 | %% Classification 32 | [ACC,RANK] = CalACC(double(classify(net,TestIn)),TestOut); 33 | end -------------------------------------------------------------------------------- /CalACC.m: -------------------------------------------------------------------------------- 1 | function [ACC,RANK] = CalACC(Label,Out) 2 | % Calculate the rank and accuracy on test set 3 | 4 | ACC = zeros(1,length(Out)); 5 | RANK = zeros(size(ACC)); 6 | for i = 1 : length(Out) 7 | ACC(i) = Out{i}(Label(i))-min(Out{i}) < 1e-8; 8 | rank = zeros(1,length(Out{i})); 9 | remain = 1 : length(Out{i}); 10 | while ~isempty(remain) 11 | current = Out{i}(remain)-min(Out{i}(remain)) < 1e-8; 12 | rank(remain(current)) = length(Out{i}) - length(remain) + 1; 13 | remain(current) = []; 14 | end 15 | RANK(i) = rank(Label(i)); 16 | end 17 | ACC = mean(ACC); 18 | RANK = mean(RANK); 19 | end -------------------------------------------------------------------------------- /Dataset.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIMK/Algorithm-Recommendation/389aa136fdd3f56b31f90f3c01ee05ffce092f1e/Dataset.mat -------------------------------------------------------------------------------- /NODE.m: -------------------------------------------------------------------------------- 1 | classdef NODE < handle 2 | % A node in the tree 3 | 4 | properties 5 | value; 6 | left = []; 7 | right = []; 8 | end 9 | methods 10 | function obj = NODE(varargin) 11 | obj.value = varargin{1}; 12 | if nargin > 1 13 | obj.left = varargin{2}; 14 | if nargin > 2 15 | obj.right = varargin{3}; 16 | end 17 | end 18 | end 19 | function out = type(obj) 20 | % Type of node: 0. operand 1. unary operator 2. binary operator 21 | if isempty(obj.left) 22 | out = 0; 23 | elseif isempty(obj.right) 24 | out = 1; 25 | else 26 | out = 2; 27 | end 28 | end 29 | function out = iscons(obj) 30 | % Whether the node is a constant 31 | out = obj.value <= 1; 32 | end 33 | function out = isscalar(obj) 34 | % Whether the node is a scalar 35 | out = ismember(obj.value,[1,3,7]) || obj.value <= 1; 36 | end 37 | function out = isbinary(obj) 38 | % Whether the node is a binary operator 39 | out = ismember(obj.value,[11,12,13,14]); 40 | end 41 | function out = isvector(obj) 42 | % Whether the node is a vector-oriented operator 43 | out = ismember(obj.value,[32,33,34,35,36]); 44 | end 45 | end 46 | end -------------------------------------------------------------------------------- /Optimizer/ABC.m: -------------------------------------------------------------------------------- 1 | function BEST = ABC(fitFun,D,N,G) 2 | % Artificial bee colony algorithm 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pobj = fitFun(Pdec); 8 | Limit = zeros(1,N); 9 | for gen = 1 : G/2 10 | % clc; fprintf('ABC %d\n',gen); 11 | % Employed bees 12 | Qdec = Pdec + (rand(size(Pdec))*2-1).*(Pdec-Pdec(randi(end,1,end),:)); 13 | Qdec = min(max(Qdec,Lower),Upper); 14 | Qobj = fitFun(Qdec); 15 | replace = Pobj > Qobj; 16 | Pdec(replace,:) = Qdec(replace,:); 17 | Pobj(replace) = Qobj(replace); 18 | Limit(~replace) = Limit(~replace) + 1; 19 | % Onlooker bees 20 | if ~any(isinf(Pobj)|isnan(Pobj)) 21 | P = cumsum(exp(-Pobj/mean(abs(Pobj)+1e-6))); 22 | else 23 | P = 1 : N; 24 | end 25 | P = P/max(P); 26 | Q = arrayfun(@(S)find(rand<=P,1),1:N); 27 | Qdec = Pdec(Q,:) + (rand(size(Pdec))*2-1).*(Pdec(Q,:)-Pdec(randi(end,1,end),:)); 28 | Qdec = min(max(Qdec,Lower),Upper); 29 | Qobj = fitFun(Qdec); 30 | replace = Pobj > Qobj; 31 | Pdec(replace,:) = Qdec(replace,:); 32 | Pobj(replace) = Qobj(replace); 33 | Limit(~replace) = Limit(~replace) + 1; 34 | % Scout bees 35 | Q = Limit > 20; 36 | Pdec(Q,:) = unifrnd(Lower(1:sum(Q),:),Upper(1:sum(Q),:)); 37 | Pobj(Q) = fitFun(Pdec(Q,:)); 38 | Limit(Q) = 0; 39 | BEST = min(Pobj); 40 | end 41 | end -------------------------------------------------------------------------------- /Optimizer/ACO.m: -------------------------------------------------------------------------------- 1 | function BEST = ACO(fitFun,D,N,G) 2 | % Ant colony optimization 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pobj = fitFun(Pdec); 8 | [Pobj,rank] = sort(Pobj); 9 | Pdec = Pdec(rank,:); 10 | w = 1/(sqrt(2*pi)*0.5*N)*exp(-0.5*(((1:N)-1)/(0.5*N)).^2); 11 | p = cumsum(w); 12 | p = p/max(p); 13 | for gen = 1 : G 14 | % clc; fprintf('ACO %d\n',gen); 15 | Mean = Pdec; 16 | Std = zeros(N,D); 17 | for i = 1 : N 18 | Std(i,:) = sum(abs(repmat(Pdec(i,:),N,1)-Pdec),1)/(N-1); 19 | end 20 | Qdec = zeros(N,D); 21 | for i = 1 : N 22 | for j = 1 : D 23 | s = find(rand<=p,1); 24 | Qdec(i,j) = Mean(s,j) + Std(s,j)*randn; 25 | end 26 | end 27 | Qdec = min(max(Qdec,Lower),Upper); 28 | Pdec = [Pdec;Qdec]; 29 | Pobj = [Pobj;fitFun(Qdec)]; 30 | [~,rank] = sort(Pobj); 31 | Pdec = Pdec(rank(1:N),:); 32 | Pobj = Pobj(rank(1:N),:); 33 | BEST = min(Pobj); 34 | end 35 | end -------------------------------------------------------------------------------- /Optimizer/CMAES.m: -------------------------------------------------------------------------------- 1 | function BEST = CMAES(fitFun,D,N,G) 2 | % Covariance matrix adaptation evolution strategy 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | % Number of parents 7 | mu = round(N/2); 8 | % Parent weights 9 | w = log(mu+0.5) - log(1:mu); 10 | w = w./sum(w); 11 | % Number of effective solutions 12 | mu_eff = 1/sum(w.^2); 13 | % Step size control parameters 14 | cs = (mu_eff+2)/(D+mu_eff+5); 15 | ds = 1 + cs + 2*max(sqrt((mu_eff-1)/(D+1))-1,0); 16 | ENN = sqrt(D)*(1-1/(4*D)+1/(21*D^2)); 17 | % Covariance update parameters 18 | cc = (4+mu_eff/D)/(4+D+2*mu_eff/D); 19 | c1 = 2/((D+1.3)^2+mu_eff); 20 | alpha_mu = 2; 21 | cmu = min(1-c1,alpha_mu*(mu_eff-2+1/mu_eff)/((D+2)^2+alpha_mu*mu_eff/2)); 22 | hth = (1.4+2/(D+1))*ENN; 23 | % Initialization 24 | Mstep = zeros(1,D); 25 | Mdec = unifrnd(Lower(1,:),Upper(1,:)); 26 | Mobj = fitFun(Mdec); 27 | BEST = Mobj; 28 | ps = zeros(1,D); 29 | pc = zeros(1,D); 30 | C = eye(D); 31 | sigma = 0.3*(Upper(1,:)-Lower(1,:)); 32 | for gen = 1 : G 33 | % clc; fprintf('CMA-ES %d\n',gen); 34 | % Generate samples 35 | for i = 1 : N 36 | Pstep(i,:) = mvnrnd(zeros(1,D),C); 37 | end 38 | Pdec = Mdec + sigma.*Pstep; 39 | Pdec = min(max(Pdec,Lower),Upper); 40 | Pobj = fitFun(Pdec); 41 | BEST = min(BEST,min(Pobj)); 42 | % Sort population 43 | [~,rank] = sort(Pobj); 44 | Pstep = Pstep(rank,:); 45 | Pdec = Pdec(rank,:); 46 | Pobj = Pobj(rank,:); 47 | % Update mean 48 | Mstep = w*Pstep(1:mu,:); 49 | Mdec = Mdec + sigma.*Mstep; 50 | % Update step size 51 | ps = (1-cs)*ps + sqrt(cs*(2-cs)*mu_eff)*Mstep/chol(C)'; 52 | sigma = sigma*exp(cs/ds*(norm(ps)/ENN-1))^0.3; 53 | % Update covariance matrix 54 | hs = norm(ps)/sqrt(1-(1-cs)^(2*(gen+1))) < hth; 55 | delta = (1-hs)*cc*(2-cc); 56 | pc = (1-cc)*pc + hs*sqrt(cc*(2-cc)*mu_eff)*Mstep; 57 | C = (1-c1-cmu)*C + c1*(pc'*pc+delta*C); 58 | for i = 1 : mu 59 | C = C + cmu*w(i)*Pstep(i,:)'*Pstep(i,:); 60 | end 61 | [V,E] = eig(C); 62 | if any(diag(E)<0) 63 | C = V*max(E,0)/V; 64 | end 65 | end 66 | end -------------------------------------------------------------------------------- /Optimizer/CSO.m: -------------------------------------------------------------------------------- 1 | function BEST = CSO(fitFun,D,N,G) 2 | % Competitive swarm optimizer 3 | 4 | Lower = zeros(N/2,D)-10; 5 | Upper = zeros(N/2,D)+10; 6 | Pdec = unifrnd(repmat(Lower,2,1),repmat(Upper,2,1)); 7 | Pvel = zeros(size(Pdec)); 8 | Pobj = fitFun(Pdec); 9 | for gen = 1 : 2*G 10 | % clc; fprintf('CSO %d\n',gen); 11 | % Divide winners and losers 12 | rank = randperm(N); 13 | loser = rank(1:end/2); 14 | winner = rank(end/2+1:end); 15 | replace = Pobj(loser) < Pobj(winner); 16 | temp = loser(replace); 17 | loser(replace) = winner(replace); 18 | winner(replace) = temp; 19 | % Update the losers 20 | R1 = repmat(rand(N/2,1),1,D); 21 | R2 = repmat(rand(N/2,1),1,D); 22 | Pvel(loser,:) = R1.*Pvel(loser,:) + R2.*(Pdec(winner,:)-Pdec(loser,:)); 23 | Pdec(loser,:) = Pdec(loser,:) + Pvel(loser,:); 24 | Pdec(loser,:) = min(max(Pdec(loser,:),Lower),Upper); 25 | Pobj(loser) = fitFun(Pdec(loser,:)); 26 | BEST = min(Pobj); 27 | end 28 | end -------------------------------------------------------------------------------- /Optimizer/DE.m: -------------------------------------------------------------------------------- 1 | function BEST = DE(fitFun,D,N,G) 2 | % Differential evolution 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pobj = fitFun(Pdec); 8 | for gen = 1 : G 9 | % clc; fprintf('DE %d\n',gen); 10 | % Mating selection 11 | [~,rank] = sort(Pobj); 12 | [~,rank] = sort(rank); 13 | Parents = randi(N,2,2*N); 14 | [~,best] = min(rank(Parents),[],1); 15 | Mdec = Pdec(Parents(best+(0:2*N-1)*2),:); 16 | % Generate offsprings 17 | Qdec = Pdec + 0.5*(Mdec(1:end/2,:)-Mdec(end/2+1:end,:)); 18 | Qdec = min(max(Qdec,Lower),Upper); 19 | Qobj = fitFun(Qdec); 20 | % Environmental selection 21 | replace = Pobj > Qobj; 22 | Pdec(replace,:) = Qdec(replace,:); 23 | Pobj(replace) = Qobj(replace); 24 | BEST = min(Pobj); 25 | end 26 | end -------------------------------------------------------------------------------- /Optimizer/FEP.m: -------------------------------------------------------------------------------- 1 | function BEST = FEP(fitFun,D,N,G) 2 | % Fast evolutionary programming 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pvel = rand(size(Pdec)); 8 | Pobj = fitFun(Pdec); 9 | for gen = 1 : G 10 | % clc; fprintf('FEP %d\n',gen); 11 | tau = 1/sqrt(2*sqrt(D)); 12 | tau1 = 1/sqrt(2*D); 13 | GaussianRand = repmat(randn(N,1),1,D); 14 | GaussianRandj = randn(N,D); 15 | CauchyRandj = trnd(1,N,D); 16 | Odec = Pdec + Pvel.*CauchyRandj; 17 | Ovel = Pvel.*exp(tau1*GaussianRand+tau*GaussianRandj); 18 | Odec = min(max(Odec,Lower),Upper); 19 | Pdec = [Pdec;Odec]; 20 | Pvel = [Pvel;Ovel]; 21 | Pobj = [Pobj;fitFun(Odec)]; 22 | Win = zeros(1,size(Pdec,1)); 23 | for i = 1 : size(Pdec,1) 24 | Win(i) = sum(Pobj(i)<=Pobj(randperm(size(Pdec,1),10))); 25 | end 26 | [~,rank] = sort(Win,'descend'); 27 | Pdec = Pdec(rank(1:N),:); 28 | Pvel = Pvel(rank(1:N),:); 29 | Pobj = Pobj(rank(1:N)); 30 | BEST = min(Pobj); 31 | end 32 | end -------------------------------------------------------------------------------- /Optimizer/GA.m: -------------------------------------------------------------------------------- 1 | function BEST = GA(fitFun,D,N,G) 2 | % Genetic algorithm 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pobj = fitFun(Pdec); 8 | for gen = 1 : G 9 | % clc; fprintf('GA %d\n',gen); 10 | % Mating selection 11 | [~,rank] = sort(Pobj); 12 | [~,rank] = sort(rank); 13 | Parents = randi(N,2,N); 14 | [~,best] = min(rank(Parents),[],1); 15 | Mdec = Pdec(Parents(best+(0:N-1)*2),:); 16 | Parent1 = Mdec(1:end/2,:); 17 | Parent2 = Mdec(end/2+1:end,:); 18 | % Simulated binary crossover 19 | beta = zeros(size(Parent1)); 20 | mu = rand(size(Parent1)); 21 | beta(mu<=0.5) = (2*mu(mu<=0.5)).^(1/21); 22 | beta(mu>0.5) = (2-2*mu(mu>0.5)).^(-1/21); 23 | beta = beta.*(-1).^randi([0,1],N/2,D); 24 | beta(rand(N/2,D)<0.5) = 1; 25 | Qdec = [(Parent1+Parent2)/2+beta.*(Parent1-Parent2)/2 26 | (Parent1+Parent2)/2-beta.*(Parent1-Parent2)/2]; 27 | % Polynomial mutation 28 | Site = rand(N,D) < 1/D; 29 | mu = rand(N,D); 30 | temp = Site & mu<=0.5; 31 | Qdec = min(max(Qdec,Lower),Upper); 32 | Qdec(temp) = Qdec(temp)+(Upper(temp)-Lower(temp)).*((2.*mu(temp)+(1-2.*mu(temp)).*(1-(Qdec(temp)-Lower(temp))./(Upper(temp)-Lower(temp))).^21).^(1/21)-1); 33 | temp = Site & mu>0.5; 34 | Qdec(temp) = Qdec(temp)+(Upper(temp)-Lower(temp)).*(1-(2.*(1-mu(temp))+2.*(mu(temp)-0.5).*(1-(Upper(temp)-Qdec(temp))./(Upper(temp)-Lower(temp))).^21).^(1/21)); 35 | Qdec = min(max(Qdec,Lower),Upper); 36 | % Environmental selection 37 | Pdec = [Pdec;Qdec]; 38 | Pobj = [Pobj;fitFun(Qdec)]; 39 | [~,rank] = sort(Pobj); 40 | Pdec = Pdec(rank(1:N),:); 41 | Pobj = Pobj(rank(1:N),:); 42 | BEST = min(Pobj); 43 | end 44 | end -------------------------------------------------------------------------------- /Optimizer/PSO.m: -------------------------------------------------------------------------------- 1 | function BEST = PSO(fitFun,D,N,G) 2 | % Particle swarm optimization 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pvel = zeros(size(Pdec)); 8 | Pobj = fitFun(Pdec); 9 | PBdec = Pdec; 10 | PBobj = Pobj; 11 | [~,index] = min(PBobj); 12 | GBdec = PBdec(index,:); 13 | for gen = 1 : G 14 | % clc; fprintf('PSO %d\n',gen); 15 | % Update particles 16 | r1 = repmat(rand(N,1),1,D); 17 | r2 = repmat(rand(N,1),1,D); 18 | Pvel = 0.4.*Pvel + r1.*(PBdec-Pdec) + r2.*(repmat(GBdec,N,1)-Pdec); 19 | Pdec = Pdec + Pvel; 20 | Pdec = min(max(Pdec,Lower),Upper); 21 | Pobj = fitFun(Pdec); 22 | % Update global best and personal best 23 | replace = Pobj < PBobj; 24 | PBdec(replace,:) = Pdec(replace,:); 25 | PBobj(replace,:) = Pobj(replace,:); 26 | [BEST,index] = min(PBobj); 27 | GBdec = PBdec(index,:); 28 | end 29 | end -------------------------------------------------------------------------------- /Optimizer/Rand.m: -------------------------------------------------------------------------------- 1 | function BEST = Rand(fitFun,D,N,G) 2 | % Random search 3 | 4 | Lower = zeros(N,D)-10; 5 | Upper = zeros(N,D)+10; 6 | Pdec = unifrnd(repmat(Lower,G,1),repmat(Upper,G,1)); 7 | Pobj = fitFun(Pdec); 8 | BEST = min(Pobj); 9 | end -------------------------------------------------------------------------------- /Optimizer/SA.m: -------------------------------------------------------------------------------- 1 | function BEST = SA(fitFun,D,N,G) 2 | % Simulated annealing 3 | 4 | Lower = zeros(1,D)-10; 5 | Upper = zeros(1,D)+10; 6 | Pdec = unifrnd(Lower,Upper); 7 | Pobj = fitFun(Pdec); 8 | BEST = Pobj; 9 | T = 0.1; 10 | sigma = 0.1*(Upper-Lower); 11 | for gen = 1 : N*G 12 | % clc; fprintf('SA %d\n',gen); 13 | mut = rand(1,D)<0.5; 14 | Qdec = Pdec; 15 | Qdec(mut) = Pdec(mut) + sigma(mut).*randn(1,sum(mut)); 16 | Qdec = min(max(Qdec,Lower),Upper); 17 | Qobj = fitFun(Qdec); 18 | delta = (Qobj-Pobj)/(abs(Pobj)+1e-6); 19 | if rand < exp(-delta/T) 20 | Pdec = Qdec; 21 | Pobj = Qobj; 22 | end 23 | T = T*0.99; 24 | sigma = sigma*0.98; 25 | BEST = min(BEST,Pobj); 26 | end 27 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithm-Recommendation 2 | 3 | A Recommender System for Metaheuristic Algorithms for Continuous Optimization Based on Deep Recurrent Neural Networks 4 | -------------------------------------------------------------------------------- /TAI_manuscript.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIMK/Algorithm-Recommendation/389aa136fdd3f56b31f90f3c01ee05ffce092f1e/TAI_manuscript.pdf -------------------------------------------------------------------------------- /generate.m: -------------------------------------------------------------------------------- 1 | function generate() 2 | % Generate a dataset 3 | clc; format compact; addpath('Optimizer'); 4 | 5 | try 6 | load Dataset Input Output 7 | catch 8 | Input = {}; 9 | Output = {}; 10 | end 11 | Algorithm = {@ABC,@ACO,@CMAES,@CSO,@DE,@FEP,@GA,@PSO,@SA,@Rand}; 12 | 13 | for i = 1 : 100000 14 | clc; fprintf('#Generated functions: %d\n#Valid samples: %d\n',i,length(Input)); 15 | % Randomly generate a function 16 | tree = generate_tree(8,12); 17 | exp = generate_tree2exp(tree); 18 | fun = generate_exp2fun(exp); 19 | Data = zeros(10,length(Algorithm)); 20 | valid = true; 21 | for r = 1 : size(Data,1) 22 | for a = 1 : size(Data,2) 23 | % Obtain the minimum value found by each algorithm, where 24 | % the number of variable is 10, the population size is 100, 25 | % the number of generations is 100. 26 | Data(r,a) = Algorithm{a}(fun,10,100,100); 27 | end 28 | if any(isnan(Data(r,:))) || any(abs(Data(r,:))>1e10) 29 | % If the function has nan value or extremely large value, 30 | % ignore the function 31 | valid = false; 32 | break; 33 | end 34 | end 35 | % If the best algorithm is statistically similar to another 36 | % algorithm, ignore the function 37 | if valid 38 | [~,best] = min(mean(Data,1)); 39 | for a = [1:best-1,best+1:size(Data,2)] 40 | [~,diff] = ranksum(Data(:,a),Data(:,best)); 41 | if ~diff 42 | valid = false; 43 | break; 44 | end 45 | end 46 | end 47 | % Save this sample 48 | if valid 49 | Input = [Input,exp]; 50 | Output = [Output,mean(Data,1)]; 51 | save Dataset Input Output 52 | end 53 | end 54 | end -------------------------------------------------------------------------------- /generate_exp2fun.m: -------------------------------------------------------------------------------- 1 | function fun = generate_exp2fun(exp) 2 | % Convert the reverse Polish expression to the function 3 | 4 | % Meaning Syntax 5 | % 1 Real number in 1-10 1.5 6 | % 2 Decision vector (x1,...,xd) 7 | % 3 First decision variable x1 8 | % 4 Translated decision vector (x2,...,xd,0) 9 | % 5 Rotated decision vector XR 10 | % 6 Index vector (1,...,d) 11 | % 7 Random number in 1-1.1 rand() 12 | % 11 Addition x+y 13 | % 12 Subtraction x-y 14 | % 13 Multiplication x.*y 15 | % 14 Division x./y 16 | % 21 Negative -x 17 | % 22 Reciprocal 1./x 18 | % 23 Multiplying by 10 10.*x 19 | % 24 Square x.^2 20 | % 25 Square root sqrt(abs(x)) 21 | % 26 Absolute value abs(x) 22 | % 27 Rounded value round(x) 23 | % 28 Sine sin(2*pi*x) 24 | % 29 Cosine cos(2*pi*x) 25 | % 30 Logarithm log(abs(x)) 26 | % 31 Exponent exp(x) 27 | % 32 sum of vector sum(x) 28 | % 33 Mean of vector mean(x) 29 | % 34 Cumulative sum of vector cumsum(x) 30 | % 35 Product of vector prod(x) 31 | % 36 Maximum of vector max(x) 32 | 33 | str = {}; 34 | for value = reshape(exp,1,[]) 35 | if value < 0 36 | str = [str,num2str(abs(value))]; 37 | else 38 | switch value 39 | case 1 % Real number in 1-10 40 | str = [str,num2str(rand*9+1)]; 41 | case 2 % Decision vector 42 | str = [str,'x']; 43 | case 3 % First decision variable 44 | str = [str,'x(:,1)']; 45 | case 4 % Translated decision vector 46 | str = [str,'[x(:,2:end),zeros(size(x,1),1)]']; 47 | case 5 % Rotated decision vector 48 | str = [str,sprintf('(x*%s)',mat2str(rand(10)))]; 49 | case 6 % Index vector 50 | str = [str,'(1:size(x,2))']; 51 | case 7 % Random number in 1-1.1 52 | str = [str,'(1+rand(size(x,1),1)/10)']; 53 | case 11 % Addition 54 | str = [str(1:end-2),sprintf('(%s+%s)',str{end-1},str{end})]; 55 | case 12 % Subtraction 56 | str = [str(1:end-2),sprintf('(%s-%s)',str{end-1},str{end})]; 57 | case 13 % Multiplication 58 | str = [str(1:end-2),sprintf('(%s.*%s)',str{end-1},str{end})]; 59 | case 14 % Division 60 | str = [str(1:end-2),sprintf('(%s./%s)',str{end-1},str{end})]; 61 | case 21 % Negative 62 | str = [str(1:end-1),sprintf('(-%s)',str{end})]; 63 | case 22 % Reciprocal 64 | str = [str(1:end-1),sprintf('(1./%s)',str{end})]; 65 | case 23 % Multiplying by 10 66 | str = [str(1:end-1),sprintf('(10*%s)',str{end})]; 67 | case 24 % Square 68 | str = [str(1:end-1),sprintf('(%s.^2)',str{end})]; 69 | case 25 % Square root 70 | str = [str(1:end-1),sprintf('sqrt(abs(%s))',str{end})]; 71 | case 26 % Absolute value 72 | str = [str(1:end-1),sprintf('abs(%s)',str{end})]; 73 | case 27 % Rounded value 74 | str = [str(1:end-1),sprintf('round(%s)',str{end})]; 75 | case 28 % Sine 76 | str = [str(1:end-1),sprintf('sin(2*pi*%s)',str{end})]; 77 | case 29 % Cosine 78 | str = [str(1:end-1),sprintf('cos(2*pi*%s)',str{end})]; 79 | case 30 % Logarithm 80 | str = [str(1:end-1),sprintf('log(abs(%s))',str{end})]; 81 | case 31 % Exponent 82 | str = [str(1:end-1),sprintf('exp(%s)',str{end})]; 83 | case 32 % Sum of vector 84 | str = [str(1:end-1),sprintf('sum(%s,2)',str{end})]; 85 | case 33 % Mean of vector 86 | str = [str(1:end-1),sprintf('mean(%s,2)',str{end})]; 87 | case 34 % Cumulative sum of vector 88 | str = [str(1:end-1),sprintf('cumsum(%s,2)',str{end})]; 89 | case 35 % Product of vector 90 | str = [str(1:end-1),sprintf('prod(%s,2)',str{end})]; 91 | case 36 % Maximum of vector 92 | str = [str(1:end-1),sprintf('max(%s,[],2)',str{end})]; 93 | end 94 | end 95 | end 96 | fun = str2func(['@(x)',str{1}]); 97 | end -------------------------------------------------------------------------------- /generate_exp2tree.m: -------------------------------------------------------------------------------- 1 | function tree = generate_exp2tree(exp) 2 | % Convert the reverse Polish expression to the tree 3 | 4 | tree = []; 5 | for i = 1 : length(exp) 6 | if exp(i) <= 10 7 | tree = [tree,NODE(exp(i))]; 8 | elseif exp(i) <= 20 9 | tree = [tree(1:end-2),NODE(exp(i),tree(end-1),tree(end))]; 10 | else 11 | tree = [tree(1:end-1),NODE(exp(i),tree(end))]; 12 | end 13 | end 14 | end -------------------------------------------------------------------------------- /generate_tree.m: -------------------------------------------------------------------------------- 1 | function tree = generate_tree(minlen,maxlen) 2 | % Randomly generate a tree 3 | 4 | % The initial tree 5 | tree = NODE(33,NODE(2)); 6 | % Probabilities of selecting each operand 7 | pOperand = [30 5 1 1 1 1 0]; 8 | pOperand = cumsum(pOperand); 9 | pOperand = pOperand./max(pOperand); 10 | % Indexes of each operand 11 | mOperand = 1 : 7; 12 | % Probabilities of selecting each operator 13 | pOperator = [15 15 10 10,... 14 | 2 2 2 5 5 2 2 3 3 3 3 3 3 1 1 1]; 15 | pOperator = cumsum(pOperator); 16 | pOperator = pOperator./max(pOperator); 17 | % Indexes of each operator 18 | mOperator = [11:14,21:36]; 19 | % Randomly generate a tree 20 | for i = 1 : randi([minlen maxlen]) 21 | % Randomly reach a leaf 22 | p = tree; 23 | while p.type > 0 24 | if p.type==1 || rand<0.5 25 | p = p.left; 26 | else 27 | p = p.right; 28 | end 29 | end 30 | % Select an operator 31 | operator = mOperator(find(rand<=pOperator,1)); 32 | if operator <= 20 % Binary operator 33 | % Select an operand 34 | operand = mOperand(find(rand<=pOperand,1)); 35 | if rand < 0.5 36 | p.left = NODE(p.value); 37 | p.right = NODE(operand); 38 | else 39 | p.left = NODE(operand); 40 | p.right = NODE(p.value); 41 | end 42 | p.value = operator; 43 | else % Unary operator 44 | p.left = NODE(p.value); 45 | p.value = operator; 46 | end 47 | end 48 | tree = injection(tree); 49 | cleaning1(tree); 50 | cleaning2(tree); 51 | cleaning1(tree); 52 | cleaning2(tree); 53 | end 54 | 55 | function tree = injection(tree) 56 | % Difficulty injection 57 | 58 | r = rand(); 59 | if r < 0.05 60 | % Noisy landscape 61 | tree = NODE(13,tree,NODE(7)); 62 | elseif r < 0.1 63 | % Flat landscape 64 | tree = NODE(27,tree); 65 | elseif r < 0.2 66 | % Multimodal landscape 67 | tree = NODE(11,tree,NODE(28,tree)); 68 | elseif r < 0.25 69 | % Highly multimodal landscape 70 | tree = NODE(11,tree,NODE(23,NODE(28,tree))); 71 | elseif r < 0.3 72 | % Linkages between all the variables and the first variable 73 | tree = injection2(tree,1); 74 | elseif r < 0.35 75 | % Linkages between each two contiguous variables 76 | tree = injection2(tree,2); 77 | elseif r < 0.4 78 | % Complex linkages between all the variables 79 | tree = injection2(tree,3); 80 | elseif r < 0.45 81 | % Different optimal values to all the variables 82 | tree = injection2(tree,4); 83 | end 84 | end 85 | 86 | function tree = injection2(tree,type) 87 | % Difficulty injection 2 88 | 89 | if isa(tree,'NODE') 90 | if tree.value == 2 91 | switch type 92 | case 1 93 | tree = NODE(12,NODE(2),NODE(3)); 94 | case 2 95 | tree = NODE(12,NODE(2),NODE(4)); 96 | case 3 97 | tree = NODE(5); 98 | case 4 99 | tree = NODE(13,NODE(6),NODE(2)); 100 | end 101 | else 102 | tree.left = injection2(tree.left,type); 103 | tree.right = injection2(tree.right,type); 104 | end 105 | end 106 | end 107 | 108 | function scalar = cleaning1(tree) 109 | % Clean the unary operators 110 | 111 | switch tree.type 112 | case 0 113 | scalar = isscalar(tree); 114 | case 1 115 | scalar = cleaning1(tree.left); 116 | if scalar && isvector(tree) 117 | % If the node is a vector-oriented operator and the child 118 | % is a scalar, replace the node with its child 119 | tree.value = tree.left.value; 120 | tree.right = tree.left.right; 121 | tree.left = tree.left.left; 122 | else 123 | if tree.value==26 && any(tree.left.value==[25,26,30]) 124 | % If the node is abs and the child is abs, log, 125 | % or sqrt, replace the node with its child 126 | tree.value = tree.left.value; 127 | tree.left = tree.left.left; 128 | elseif any(tree.value==[25,26,30]) && tree.left.value==26 129 | % If the node is abs, log, or sqrt and the child is 130 | % abs, replace the child with its child 131 | tree.left = tree.left.left; 132 | elseif tree.value==21 && tree.left.value==21 || tree.value==22 && tree.left.value==22 133 | % If both the node and child are negative or 134 | % reciprocal, replace the node with its child's child 135 | tree.value = tree.left.left.value; 136 | tree.right = tree.left.left.right; 137 | tree.left = tree.left.left.left; 138 | elseif tree.value==24 && tree.left.value==25 || tree.value==25 && tree.left.value==24 || tree.value==30 && tree.left.value==31 || tree.value==31 && tree.left.value==30 139 | % If both the node and child are square and sqrt or log 140 | % and exp, replace the node with its child's child 141 | tree.value = tree.left.left.value; 142 | tree.right = tree.left.left.right; 143 | tree.left = tree.left.left.left; 144 | elseif tree.value==21 && tree.left.value==12 145 | % If the node is negative and the child is subtraction, 146 | % replace the node with its child then exchange its 147 | % children 148 | tree.value = 12; 149 | tree.right = tree.left.left; 150 | tree.left = tree.left.right; 151 | elseif tree.value==22 && tree.left.value==14 152 | % If the node is reciprocal and the child is division, 153 | % replace the node with its child then exchange its 154 | % children 155 | tree.value = 14; 156 | tree.right = tree.left.left; 157 | tree.left = tree.left.right; 158 | end 159 | end 160 | scalar = scalar || isvector(tree) && tree.value~=34; 161 | case 2 162 | scalar1 = cleaning1(tree.left); 163 | scalar2 = cleaning1(tree.right); 164 | scalar = scalar1 && scalar2; 165 | end 166 | end 167 | 168 | function cons = cleaning2(tree) 169 | % Clean the binary operators 170 | 171 | switch tree.type 172 | case 0 173 | cons = iscons(tree); 174 | case 1 175 | cons = cleaning2(tree.left); 176 | case 2 177 | cons1 = cleaning2(tree.left); 178 | cons2 = cleaning2(tree.right); 179 | cons = cons1 && cons2; 180 | if cons 181 | % If both the children are constants, change the node to a 182 | % constant 183 | tree.value = 1; 184 | tree.left = []; 185 | tree.right = []; 186 | elseif tree.right.value == 21 187 | % If the node is addition and the right child is negative, 188 | % change the node to subtraction and replace the right 189 | % child with its child 190 | if tree.value == 11 191 | tree.value = 12; 192 | tree.right = tree.right.left; 193 | % If the node is subtraction and the right child is 194 | % negative, change the node to addition and replace the 195 | % right child with its child 196 | elseif tree.value == 12 197 | tree.value = 11; 198 | tree.right = tree.right.left; 199 | end 200 | elseif tree.right.value == 22 201 | % If the node is multiplication and the right child is 202 | % reciprocal, change the node to division and replace the 203 | % right child with its child 204 | if tree.value == 13 205 | tree.value = 14; 206 | tree.right = tree.right.left; 207 | % If the node is division and the right child is 208 | % reciprocal, change the node to multiplication and replace 209 | % the right child with its child 210 | elseif tree.value == 14 211 | tree.value = 13; 212 | tree.right = tree.right.left; 213 | end 214 | elseif tree.left.value==21 && tree.value==11 215 | % If the node is addition and the left child is negative, 216 | % change the node to subtraction, replace the left child 217 | % with its child, then exchange the node's children 218 | tree.value = 12; 219 | temp = tree.right; 220 | tree.right = tree.left.left; 221 | tree.left = temp; 222 | elseif tree.left.value==22 && tree.value==13 223 | % If the node is multiplication and the left child is 224 | % reciprocal, change the node to division, replace the left 225 | % child with its child, then exchange the node's children 226 | tree.value = 14; 227 | temp = tree.right; 228 | tree.right = tree.left.left; 229 | tree.left = temp; 230 | elseif isbinary(tree.left) && cons2 231 | if all(ismember([tree.value,tree.left.value],[11,12])) || all(ismember([tree.value,tree.left.value],[13,14])) 232 | if iscons(tree.left.left) || iscons(tree.left.right) 233 | % If the left child is a binary operator, at least 234 | % one of the left child's children is a constant, 235 | % and the right child is a constant, replace the 236 | % node with its left child 237 | tree.value = tree.left.value; 238 | tree.right = tree.left.right; 239 | tree.left = tree.left.left; 240 | end 241 | end 242 | elseif cons1 && isbinary(tree.right) 243 | if all(ismember([tree.value,tree.right.value],[11,12])) || all(ismember([tree.value,tree.right.value],[13,14])) 244 | if iscons(tree.right.right) 245 | % If the right child is a binary operator, the 246 | % right child's right child is a constant, and the 247 | % left child is a constant, replace the right child 248 | % with its left child 249 | tree.right = tree.right.left; 250 | elseif iscons(tree.right.left) 251 | % If the right child is a binary operator, the 252 | % right child's left child is a constant, and the 253 | % left child is a constant, replace the right child 254 | % with its right child then change the node's 255 | % operator 256 | if tree.value == tree.right.value 257 | if tree.value <= 12 258 | tree.value = 11; 259 | else 260 | tree.value = 13; 261 | end 262 | else 263 | if tree.value <= 12 264 | tree.value = 12; 265 | else 266 | tree.value = 14; 267 | end 268 | end 269 | tree.right = tree.right.right; 270 | end 271 | end 272 | elseif isbinary(tree.left) && isbinary(tree.right) 273 | if all(ismember([tree.left.value,tree.value,tree.right.value],[11,12])) || all(ismember([tree.left.value,tree.value,tree.right.value],[13,14])) 274 | if (iscons(tree.left.left)||iscons(tree.left.right)) && iscons(tree.right.right) 275 | % If both the left and right children are binary 276 | % operators, at least one of the left child's 277 | % children is a constant, and the right child's 278 | % right child is a constant, replace the right 279 | % child with its left child 280 | tree.right = tree.right.left; 281 | elseif (iscons(tree.left.left)||iscons(tree.left.right)) && iscons(tree.right.left) 282 | % If both the left and right children are binary 283 | % operators, at least one of the left child's 284 | % children is a constant, and the right child's 285 | % left child is a constant, replace the right child 286 | % with its right child then change the node's 287 | % operator 288 | if tree.value == tree.right.value 289 | if tree.value <= 12 290 | tree.value = 11; 291 | else 292 | tree.value = 13; 293 | end 294 | else 295 | if tree.value <= 12 296 | tree.value = 12; 297 | else 298 | tree.value = 14; 299 | end 300 | end 301 | tree.right = tree.right.right; 302 | end 303 | end 304 | end 305 | end 306 | end -------------------------------------------------------------------------------- /generate_tree2exp.m: -------------------------------------------------------------------------------- 1 | function exp = generate_tree2exp(tree) 2 | % Convert the tree to the reverse Polish expression 3 | 4 | switch tree.type 5 | case 0 6 | exp = tree.value; 7 | case 1 8 | exp = [generate_tree2exp(tree.left),tree.value]; 9 | case 2 10 | exp = [generate_tree2exp(tree.left),generate_tree2exp(tree.right),tree.value]; 11 | end 12 | end -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | function main() 2 | % Compare the accuracy of several methods 3 | clc; format compact; addpath('Optimizer'); 4 | 5 | type = 1; % 1. Train a new model 2. Load an existing model 6 | 7 | %% Load dataset 8 | load Dataset Input Output; 9 | train = 1 : round(length(Output)*0.8); 10 | test = setdiff(1:length(Output),train); 11 | TrainIn = Input(train); 12 | TrainOut = Output(train); 13 | TestIn = Input(test); 14 | TestOut = Output(test); 15 | 16 | %% Training and test 17 | [ACC,RANK] = AR_WB(type,TrainIn,TrainOut,TestIn,TestOut) 18 | end --------------------------------------------------------------------------------