Asked by Parker Dean
on 19 Jul 2019 at 18:27

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?

Answer by Matt J
on 19 Jul 2019 at 20:39

Edited by Matt J
on 19 Jul 2019 at 20:56

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

Parker Dean
on 20 Jul 2019 at 15:24

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
on 20 Jul 2019 at 19:13

The use of nan() was just to pre-allocate the output.

Sign in to comment.

Opportunities for recent engineering grads.

Apply Today
## 0 Comments

Sign in to comment.