Why does the genetic algorithm in this case run only for one generation? and it's very slow.

I'm using ga() for optimizing a 4-variable objective function. Below is my scrpit and attached file is the result.
ga runs only for one generation and it took 16412 seconds. In options I set MaxTime to be 5000 though. In this one generation, my objective function was called 150 times. How can I get more number of generations?
start_time = tic();
A = [];
b = [];
Aeq = [];
beq = [];
lb =[0.1; 0; 50; 0.1];
ub = [0.4; 0.9; 4000; 0.9];
to = [ 0.15, 0, 300, 0.3];
options = optimoptions('ga','display','iter', 'MaxTime', 5000);
[t,fval,exitflag,output] = ga(@objectivefun,4,A,b,Aeq,beq,lb,ub,@nonlco, options); % genetic algorithm
%[t,fval,exitflag,output] = particleswarm(@objectivefun, 4, lb, ub ); % Particle swarm optimization
%[t,fval,exitflag,output] = simulannealbnd(@objectivefun, t, lb,ub); %simulated annealing algorithm
toc(start_time);
function f = objectivefun(t)
load('G.mat');
load('Load');
p = t(1);
Trigger = t(2);
bgt = t(3);
alpha = t(4);
N = numnodes(G);
iter = 1;
tmax = 30;
M_iter = zeros(iter, tmax);
for jj = 1:iter
[G_dmg,~,~, needRemoveNode,LoadneedDist,M] = Load_initial(G,8,0,350,0.2,Load);
alreadyCalled = false; % Say that decision and implement have not been called yet.
for tt = 3: tmax
if any(needRemoveNode)|| ~any(needRemoveNode)
[G_dmg,LoadneedDist,needRemoveNode,M] = Load_Stages(G_dmg,needRemoveNode,LoadneedDist,M);
end
if (M(end) >= (Trigger * N)) && ~alreadyCalled % triggering level
% Calling for the very first time if we get here.
[G_dmg, Nodes_p] = Loads_decision(G_dmg);
[G_dmg] = Loads_implement(G_dmg, Nodes_p, p, bgt, alpha);
alreadyCalled = true; % Set flag to indicate we've called it.
elseif alreadyCalled
% Once they've been called already, call them regardless of the "if" test.
[G_dmg, Nodes_p] = Loads_decision(G_dmg);
[G_dmg, M] = Loads_implement(G_dmg, Nodes_p, M, p, bgt, alpha);
end
end
M_iter(jj,:)=M;
% S = std(M_iter);
% SE = S/sqrt(size(M_iter,1));
end
Mavg = mean(M_iter,1);
[~, maxidx] = max(Mavg);
f = find( (Mavg <= 0.05 * N) & (maxidx <= 1:length(Mavg)), 1 );
if isempty(f)
f = 31;
end
end
function [c, ceq] = nonlco (t)
c = [];
ceq = [];
end

15 Kommentare

load('G.mat');
load('Load');
Avoid using load() inside an optimization function. Load the variables before and pass the values in.
We have no idea how fast Loads_implement or Loads_decision or Load_Stages are, so we have no way of guessing what the slow operations are.
Question: is Loads_implement detecting how many output arguments are being used, and does less calculation if there is only one output argument?
Hi Walter, Kindly see attached my four functions and G&Load.
How can I pass both G and Load when I am calling objectivefun from ga()?
load('G.mat');
load('Load.mat');
[t,fval,exitflag,output] = ga(@objectivefun, 4,A,b,Aeq,beq,lb,ub,@nonlco, options);
function f = objectivefun(t, G, Load)
...
end
I didn't know if I fully understood your question "Question: is Loads_implement detecting how many output arguments are being used, and does less calculation if there is only one output argument? " So that why I attached all functions in my previous comment, I'm sorry.
The Elapsed time is 115.022876 seconds when I ran my four functions without including the optimization part (and I did One iteration only).
Please look at this more closely:
if (M(end) >= (Trigger * N)) && ~alreadyCalled % triggering level
% Calling for the very first time if we get here.
[G_dmg, Nodes_p] = Loads_decision(G_dmg);
[G_dmg] = Loads_implement(G_dmg, Nodes_p, p, bgt, alpha);
alreadyCalled = true; % Set flag to indicate we've called it.
elseif alreadyCalled
% Once they've been called already, call them regardless of the "if" test.
[G_dmg, Nodes_p] = Loads_decision(G_dmg);
[G_dmg, M] = Loads_implement(G_dmg, Nodes_p, M, p, bgt, alpha);
end
In the two if cases, there is no difference in the calls to Loads_decision.
In the two if cases, the first difference in the calls to Loads_implement is that the first call does not return M, but the second call returns M. But if you look at the code for Loads_implement, the M that is passed in is passed out again unchanged in every case, so the effect is the same as if you do not assign to M in the call.
In the two if cases, the second difference in the calls to Loads_implement is that the first call does not pass in M, but ths second call passes in M. But let us look at the way that M is used in the function:
function [G_rec, M] = Loads_implement(G_dmg, Nodes_p, M, p, bgt, alpha,G_dmg_at_index_tt)
If you pass in M, then it matches the M in the calling sequence, and you get a normal looking situation where you are passing in 6 parameters and nargin is 6 and the names in the function definition line up nicely with the names passed in.
But now let us look at what happens if you do not pass in M. In that case, nargin is 5, and what is passed in as p is received into the M matrix, and what is passed in as bgt is received in the alpha matrix, and what is passed in as alpha is received into the bgt matrix. But then if you examine the code for nargin == 5, it is obviously using the bgt matrix as if it means the same thing as the bgt from the calling function, but because you did not pass in M, all the variables "fell down" one slot in matching to names, and the bgt variable inside the function holds the information you passed in as alpha .
If you want the Loads_implement to use a different algorithm for the two cases, then you need to find a way to still match up the variable names properly for the values you do pass in.
For instead of not passing in M at all (causing all the positions to fall down), pass in M as [] and use nargin and isempty(M) to detect which case you want to execute.
I should pass M in and return it in the two if cases. My bad. Thank you so much for detecting this mess.
if (M(end) >= (Trigger * N)) && ~alreadyCalled % triggering level
% Calling for the very first time if we get here.
[G_dmg, Nodes_p] = Loads_decision(G_dmg);
[G_dmg, M] = Loads_implement(G_dmg, Nodes_p, M, p, bgt, alpha); % FIXED
alreadyCalled = true; % Set flag to indicate we've called it.
elseif alreadyCalled
% Once they've been called already, call them regardless of the "if" test.
[G_dmg, Nodes_p] = Loads_decision(G_dmg);
[G_dmg, M] = Loads_implement(G_dmg, Nodes_p, M, p, bgt, alpha);
end
As for the variables, How can I load it outside the optimization function and pass it in? I'm running the optimization right now and non of the generations have been displayed.
Okay, now another question:
Suppose that you have not set alreadyCalled and M(end)>= (Trigger*N) is false. Then the first part of the if is false and the second part is ~false == true, and false && true is false, so you move on to the elseif . Then in the elseif alreadyCalled is tested, and by hypothesis the variable is false so the elseif is false, so you will skip the elseif body, and will not have called any functions and will not have set any variables. So far so good, that sounds reasonable.
Now suppose you have not set alreadyCalled and M(end)>= (Trigger*N) is true. Then the first part of the if is true, and the second part is ~false == true, and true && true is true, so you execute the body of the if and call the functions and set alreadyCalled to true. Seems reasonable.
Now suppose that you have set alreadyCalled and M(end)>= (Trigger*N) is false. Then the first part of the if is false and the second part is ~true == false, and false && false is false, so you move on to the elseif. Then in the elseif alreadyCalled is tested, and by hypothesis the variable is true, so the elseif is true, so you will execute the functions (and not change alreadyCalled . Hmmm --- maybe this is okay ?? Let's keep looking
Now suppose you have set alreadyCalled and M(end)>=(Trigger*N) is true. Then the first part of the if is true and the second part is ~true == false, and true && false is false, so you move on to the elseif. Then in the elseif alreadyCalled is tested, and by hypothesis the variable is true, so the elseif is true, so you will execute the functions (and not change alreadyCalled . Hmmm -- maybe this is okay ??
But... do you really want to be calling the functions in the elseif branch no matter whether M(end)>=(Trigger*N) is true or false ?? If that is deliberate, the code could be written more clearly by making the if test only alreadyCalled and have it call the functions, and then have the elseif check M(end)>=(Trigger*N) only
But... do you really want to be calling the functions in the elseif branch no matter whether M(end)>=(Trigger*N) is true or false ?? (EDITED) Yes.
I had revised my code again in the morning and I figured out that it was not writtern clear enough as it misled me last night. Thank you so much, Walter. I never had this fruiful discussion before. And I really like the flow in your comment.
I followed Alan Weiss instruction below but unfortunately the ga algorithm is still very slow. It has been running for more than three hours and MATLAB has not displayed the first generation yet.
I got the error of Not enough input arguments when I did this:
load('G.mat');
load('Load.mat');
[t,fval,exitflag,output] = ga(@objectivefun, 4,A,b,Aeq,beq,lb,ub,@nonlco, options);
function f = objectivefun(t, G, Load)
...
end
How can I pass in G and Load to @objectivefunc from inside ga? I couldn't implement this exapmle in my script.
As explained in Passing Extra Parameters, instead of
ga(@objectivefun...
you most likely should have
ga(@(x)objectivefun(x,G,Load)...
where your objectivefun code should be
function y = objectivefun(x,G,Load)
Alan Weiss
MATLAB mathematical toolbox documentation
Thank you so much Alan. We thought that loading G and Load inside the optimization function is the main reason why ga() is slow. I don't really know what makes it incredibly slow.
Okay, I think ga() in MATLAB will be very slow when we pass in a Graph object. Previously I used a graph that has 5000 nodes and 10000 edges. Today I used a graph that consists only of 34 nodes and 78 edges, and ga() was able to run 5 generations. Kindly see attached. I'm not sure if there is a way to expedite the ga optimization in MATLAB when we pass a graph object to the objective function.
Note: I'm using windows computer, intel CORE i9 and 64GB RAM.
Please post your revised code. I still have concerns about your calculations.
Hi Walter,
I changed it back to the old version after debugging it. Please see the attached files.

Melden Sie sich an, um zu kommentieren.

Antworten (0)

Gefragt:

am 2 Dez. 2021

Kommentiert:

am 4 Dez. 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by