Question

I am simulating a batch evaporator in Matlab. The genetic algorithm varies several starting variables x (such as size, max. mass of working fluid, the overall number of evaporators used ...) and the goal is to maximize the efficiency. So my function evaporator(x) returns the negative efficiency which is minimized by the algorithm.
Besides the efficiency, there are several other values calculated. One is the duration of the simulated cycle (NOT the runtime of the calculation itself!). As a constraint, the duration of the whole evaporation cycle should, depending on the number of evaporators, not be to short (e.g. if three evaporators are used, the whole cycle should take at least 3*5s = 15s).
I know that I can easily use the nonlinear constraints option of ga (nonlcon). In this case I would just have to do the same calculations from evaporator(x) again, but return the calculated duration this time. The problem is, that I have to call an external DLL several thousand times per run and the calculations become really slow. Therefore I really want to avoid running all the calculations twice.
Is it somehow possible, that evaporator(x) returns both the negative efficiency and the duration at the same time? ga should then minimize the negative efficiency and evaluate the duration regarding the constraints. I thought about nesting the evaporator(x) inside an anonymous function, but I think my function still has to be called twice then?

I had good experience with the Multiobjective Optimization of the efficiency and the duration at the same time, but unfortunately the gamultiobj algorithm cannot handle integer variables.

At the moment I am using a penalty function on short durations inside evaporator(x), but I think, that the constraints handling of the ga algorithm would be better than this.

Edit: So it got a bit more complicated, but in the end it is working:

function [ returnValue ] = switchHXoutput( requestedCase, inputs )
%SwitchHXoutput returns fitness value or duration depending on requested
%case

persistent fitnessValue duration oldInputs;

if isempty(oldInputs)
    oldInputs = {}; %initialize oldInputs as cell
end


[isAllreadyCalculated, iOldInput] =...
ismember(cell2mat(inputs), cell2mat([oldInputs{:}]), 'rows'); 

if isempty(oldInputs) || ~isAllreadyCalculated
    [fitnessValue(end+1), duration(end+1)] = lengthyCalculation(inputs); %add current results to persistent array
    oldInputs(end+1) = {inputs}; %add current inputs to persistent array
    returnValue = [fitnessValue(end), duration(end)];
else
    returnValue = [fitnessValue(iOldInput), duration(iOldInput)]; % return old values
end

if strcmp(requestedCase, 'FitnessValue')
    returnValue = returnValue(1);
elseif strcmp(requestedCase, 'duration')
    returnValue = returnValue(2);
else
    error('MyApp:SelectOutput','Requested case not supported')
end

end %function

I know that a growing cell array isn't exactly fast. But as my lengthyCalculation takes about 2 minutes for each call I am still saving a lot of time. Furthermore the best individuals of each generation are used again in the next generation. So in this case the saved values can be used instead of recalculating them again. The code works also fine with parallel computation. Normally the fitness value and the duration are calculated by the same worker. Only for following generations the results can be on another worker.

Was it helpful?

Solution

One option is to include some persistent state, which records both the efficiency and duration computed on the last run (this is memoization) and decide which to return based on the function inputs.

For example,

function return_value = evaporator(method, value, inputs)

  persistent efficiency duration;

  if strcmp(method, 'recalculate')
      % Some lengthy calculation goes here
      efficiency = inputs + 1;
      duration   = inputs + 10;
      pause(5);
  end

  switch value
    case 'efficiency'
      return_value = efficiency;
    case 'duration'
      return_value = duration;
  end

end

The result is

>> evaporator('recalculate', 'efficiency', 10)
11
>> evaporator('memoized', 'duration')
20
>> evaporator('recalculate', 'efficiency', 20)
21
>> evaporator('memoized', 'duration')
30
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top