MATLAB Answers

0

Using fmincon on a vector of anonymous functions

Asked by Parker Dean on 19 Jul 2019
Latest activity Commented on by Matt J
on 20 Jul 2019
I am trying to run an optimization problem on some equations simultaneously, and need to find a way to accomplish it without using eval. I have a function (layerEq) with parameter N which creates a cell array of N anonymous functions, describing the problem I am optimizing. Each of these equations anonymous equations recieves a vector of length N, and returns a real number.
function [eqCArray] = layerEq(numLayers, Int, T)
I = int2str(Int);
B = sprintf('%.3f',T);
N = numLayers;
eqCArray = cell(1, N);
for i = N:-1:1
%
% Synthesis of my equations based on N, not relevant to optimization question
%
end
eqCArray = cellfun(@str2func,eqCArray,'UniformOutput',false);
end
In a script, I want to call this function, and make a statement like the following.
exposureEqs = layerEq(numLayers, I, B);
E = @(A) [exposureEqs{1}(A), exposureEqs{2}(A), exposureEqs{3}(A), exposureEqs{4}(A)];
When numLayers = 4, this line executes correctly, and I get the desired result. However, instead of hard coding this vector E, I want to make it of length numLayers (AKA: N, as I described it earlier), with all the elements from the cell array exposureEqs.
So far, I have been unable to accomplish this without the use of eval. I tried using the help section in the documentation "Alternatives to the Eval Function", but wasn't able to find anything relevant to my question. Currently, my script looks as such:
I = 33.6;
B = 0.75;
numLayers = 4;
exposureMax = 3025;
exposureMin = 2975;
%Starter Vector
t0 = linspace(2, 10, numLayers);
%Create equations using layerEq
exposureEqs = layerEq(numLayers, I, B);
%Setup for automatic data separation
arrayStr = '';
elementStr = '';
v = ones(1, numLayers);
%Automatic Data Separation Loop: executes as if I have hardcoded the values
%into anonymous functions myself, but for the appropriate number of layers.
for i = 1:numLayers
dataStr = ['e' int2str(i) ' = @(A) exposureEqs{' int2str(i) '}(A)'];
elementStr = [elementStr 'e' int2str(i) '(A) '];
eval(dataStr); %Executes each line of code assigning a function
end
eval(['E = @(A) [' elementStr '];'])
% E = @(A) [exposureEqs{1}(A), exposureEqs{2}(A), exposureEqs{3}(A), exposureEqs{4}(A)]; %LINE RUNS
%Standard Deviation function to be minimized in the optimizer
stdDev = @(A) std(E(A));
%Writing out bounds
lb = zeros(size(t0));
ub = inf(size(t0));
%Calculating and storing nonlinear constraints
nonlcon = @(A) avgCon(E, A, exposureMin, exposureMax);
%Optimizer Function
x = fmincon(stdDev, t0, [], [], [], [], lb, ub, nonlcon);
%Values by Layer
y = E(x);
z = stdDev(x);
disp(x)
disp(y)
disp(['Standard Deviation: ' sprintf(sprintf('%.3f', z))])
function [c, ceq] = avgCon(E, A, exposureMin, exposureMax)
c(1) = mean(E(A)) - exposureMax;
c(2) = -1 * mean(E(A)) + exposureMin;
ceq = [];
end
To make things more clear, I am trying to minimize the standard deviation of my equations by optimizing the vector of variables they recieve. I also have a non-linear constraint to make sure the mean of my equations is between the two variables exposureMin and exposureMax.
In summary: how can I create that anonymous function E correctly, based on the value of numLayers, without using the eval command?

  0 Comments

Sign in to comment.

1 Answer

Answer by Matt J
on 19 Jul 2019
Edited by Matt J
on 19 Jul 2019
 Accepted Answer

I would recommend that you implement E(A) through a non-anonymous function, as below. Note that I have changed your objective to var(E(A)) in order to help comply with differentiability requirements of fmincon. I hope you realize that all of your exposureEqs are expected by fmincon to be smooth/differentiable as well.
x = fmincon(@(A) var(Efun(A,exposureEqs)) , t0, [], [], [], [], lb, ub,...
@(A) avgCon(A, exposureEqns, exposureMin, exposureMax));
function E=Efun(A,exposureEqs)
N=numel(exposureEqs);
E=nan(N,1);
for i=1:N
E(i)=exposureEqs{i}(A);
end
end
function [c, ceq] = avgCon(A, exposureEqns,exposureMin, exposureMax)
m=mean(Efun(A , exposureEqns));
c(1) = m - exposureMax;
c(2) = exposureMin-m;
ceq = [];
end

  2 Comments

Thank you Matt, this worked very well! Is there a reason that creating an array of NaN is used to store the exposureEqs in Efun? I am still learning the ropes of which data types to use when pre-allocating vectors that I will be adding N elements to.
Also thank you for noting the issue with using std, I hadn't thought of the differentiability issue.
The use of nan() was just to pre-allocate the output.

Sign in to comment.