gamultiobj failure when starting with a whole feasible population

8 views (last 30 days)
Hello, I am using gamultiobj of Matlab R2016b only with non-linear constraints. If I try to start the optimisation with a specified initial population which has all the individual feasible, I get the following error:
Assignment has more non-singleton rhs dimensions than non-singleton subscripts
Error in objAndConVectorizer (line 33)
Fvals(i,:) = feval(objFcn,(pop(i,:)));
Error in gamultiobjMakeState (line 118)
[~,C,Ceq,isFeas] =
objAndConVectorizer(state.Population(1:initScoreProvided,:), ...
Error in gamultiobjsolve (line 8)
state =
gamultiobjMakeState(GenomeLength,FitnessFcn,ConstrFcn,output.problemtype,options);
Error in gamultiobj (line 274)
[x,fval,exitFlag,output,population,scores] = gamultiobjsolve(FitnessFcn,nvars,
...
Caused by:
Failure in user-supplied fitness function evaluation. Cannot continue.
Instead, if I choose only the first individual of my initial population such that it is infeasible, the optimisation runs with no problem (thus fitness function has no problem). Unfortunately this is an issue when I want to start a new optimisation using the last population of the previous run, to keep on iterating, because I am forced to drop a good individual and to replace the first entry of the population with an infeasible element. If I do not use non-linear constraint, this problem does not occur, even this the error attributes the failure to the fitness function. I have been using a variety of fitness and non-linear constraint functions and I have had this error in all the cases. The way I call the optimiser is standard:
[x,fval,exitflag,output,population,score] = ...
gamultiobj(@FitnessFun,nvars,[],[],[],[],lb,ub,@ConstraintFun,options);
Thanks for help

Accepted Answer

Steve Grikschat
Steve Grikschat on 27 Nov 2017
Hi,
From the stack trace, you can see that the solver calls the fitness function with a row vector. It should be a 1-by-nvars vector (you could check to be sure). The result of that evaluation is not a vector, but a matrix (or possibly an N-D array), which results in an error.
See this example code that mimics the error code in the stack:
popSize = 4; numObj = 2;
Fvals = Inf(popSize,numObj);
Fvals(2,:) = rand(2,2)
This is likely because of a mismatch in dimensionality between what your fitness function returns and what the solver expects. The solver always requires a vector of function values. The fitness function may not be consistent in how it outputs the results.
If you call your fitness function with the first row of the feasible initial population, what size is the output? What about with the infeasible member (as a row)?
gamultiobj must determine some of the sizes from the input arrays at run-time. Therefore, it can derive numbers that differ from what you expect. Also note that the 1st individual (row) is used for many of the validation checks on the function. So, I wonder if the solver would still error if you put the 1 infeasible point in the middle of the population.
It might also help determine the other behaviors if you could give the other parameters:
  • The size of the InitialPopulation
  • The options.PopulationSize value
  • Number of variables (the 2nd input)
  • CreationFcn
  2 Comments
AM
AM on 3 Dec 2017
Dear Steve, thank you for your response. The error I get doesn't seem related to the fitness function I am using. I use optimisation for many purposes and I have employed fitness functions of different complexity, with several values of population size and design variables. As you say, gamultiobj performs several checks before entering the main loop and it is there that something goes wrong. I am sure that the fitness function always returns the correct output, a row vector with length the number of objectives, as I expect (for instance I can disp the fit at each call). In debug mode, I can see that all the initial validations are correct and the entire population is evaluated once succesfully. After that, in gamultiobjMakeState there is a call to objAndConVectorizer (line 118):
% If the initial score (objective values) were given for any members of the
% population, then we must go back and evaluate the constraints on those
% points since it can't be given by the user.
if (initScoreProvided > 0) && (state.mAll > 0)
fakeFitness = @(x) NaN(numObj,size(x,2));
if strcmpi(options.Vectorized, 'off')
[~,C,Ceq,isFeas] = objAndConVectorizer(state.Population(1:initScoreProvided,:), ...
fakeFitness,ConstrFcn,numObj,state.mIneq,state.mEq,options.SerialUserFcn, ...
true(initScoreProvided,1),options.TolCon);
else
...
Here initScoreProvided is 1 and thus state.Population(1:initScoreProvided,:) is a single row. The Fitness inside objAndConVectorizer is evaluated according to the fakeFitness, which is NaN. The error is generated in the catch statement of lines 54-67:
catch userFcn_ME
if iscell(pop) % if it is a custom PopulationType
Fvals = objFcn(pop);
if hasNonlinCon
[C,Ceq] = nonlconFcn(pop);
isFeas = isFeas & isNonlinearFeasible(C,Ceq,TolCon);
end
else
gads_ME = MException('globaloptim:objAndConVectorizer:fitnessEvaluation', ...
'Failure in user-supplied fitness function evaluation. Cannot continue.');
userFcn_ME = addCause(userFcn_ME,gads_ME);
rethrow(userFcn_ME)
end
end
Indeed, iscell(pop) gives false (the population is 1x3 double) and than throws the exception. I do not understand the reason of this behaviour since I am not aware of the whole loop of gamultiobj. Anyway, I can say that this occurs only when the first individual in the population is feasible. When it is infeasible, everything is equal to the previous case, but the catch is totally skipped and so no exception is thrown. If the infeasible individual is in the middle of the population and the first is feasible, I have the error. As regards the input values you requested, they appear all correct according to the fitness function I am using (e.g. nvars = 3, options.PopulationSize=15, size(InitialPopulation)=15-by-3). For CreationFcn, since I use to provide the initial population (I usually choose it from a DOE), I do not change any default option. Thanks
Steve Grikschat
Steve Grikschat on 4 Dec 2017
Hi,
I can verify that there was a bug in that portion of the code which was fixed in R2017a.
The bug was in the line
fakeFitness = @(x) NaN(numObj,size(x,2));
The 2nd argument to size should be "1".
The reason that the 1st member of the population matters here is that this block of code is only used to evaluate the constraints on the part of the population with the initial score provided (aka, the index "initScoreProvided" which is 1).
The way gamultiobj handles evaluations with nonlinear constraints is to evaluate the constraints first, and then evaluate the objective only if it is feasible.
So, when the 1st member is infeasible, this fakeFitness eval is skipped.
Sorry for the confusion and the error. Again, this is fixed in R2017a and later.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!