Using fmincon on a vector of anonymous functions

9 views (last 30 days)
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?

Accepted Answer

Matt J
Matt J on 19 Jul 2019
Edited: Matt J on 19 Jul 2019
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
Parker Dean
Parker Dean on 20 Jul 2019
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.
Matt J
Matt J on 20 Jul 2019
The use of nan() was just to pre-allocate the output.

Sign in to comment.

More Answers (0)

Categories

Find more on Get Started with Optimization Toolbox in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!