Create the objective function for fmincon solver using for loop

7 visualizzazioni (ultimi 30 giorni)
I have been trying to create my objective function using a for loop as the number of decision variables should be changed. However, this parameter based upon which the number of decision variables is varied is fixed at the very beginning and maintained constant throughout the optimization process period. To clarify my point here is the part of the code I have written:
if true
N = 6;
for i = 1 : N - 1
if i == 1
Afun = @(x)((x(i) - xmin) * (Nonlinear_curve(i) - Nonlinear_curve(xmin))/2);
elseif 1 < i <= N - 2
Afun = @(x)((x(i) - x(i - 1)) * (Nonlinear_curve(i) - Nonlinear_curve(i - 1))/2);
else
Afun = @(x)((xmax - x(i - 1)) * (Nonlinear_curve(xmax) - Nonlinear_curve(i - 1))/2);
end
if i==1
FUN = @(x) Afun(x);
else
FUN = @(x) Afun(x) + FUN(x);
end
end
end
Following this and of course, specifying the constraints and the bounds, the foregoing created FUN is called in the fmincon. Although everything seems to be fine, when I run the code, the results are not rational as compared to the correct results that I achieved without employing the "for loop" for a certain number of Decision variables. I would appreciate if you could suggest any solution how to create the objective function using for loop?
  2 Commenti
Are Mjaavatten
Are Mjaavatten il 4 Dic 2017
Should it be
Nonlinear_curve(x(i))
rather than
Nonlinear_curve(i)
?
Also, in your construct
if true
. . .
end
you can safely remove the first and last line.
Russell Grm
Russell Grm il 4 Dic 2017
Thank you very much for your swift response! yeah, that's correct! it was my first mistake. However, a new error appeared which I believe it has something to do with this line of the code:
FUN = @(x) Afun(x) + FUN(x);
and here is the error being presented in the command window
Error in test>@(x)((x(i)-x(i-1))*(Nonlinear_curve(x(i))-Nonlinear_curve(x(i-1)))/2)
Error in test>@(x)Afun(x)+FUN(x)
Could anyone please assist me in forming the Objective function using a for loop in which the number of DVs is variable.

Accedi per commentare.

Risposta accettata

Walter Roberson
Walter Roberson il 6 Dic 2017
If the final function handle is going to be executed a number of times, then if you have the symbolic toolbox, I recommend that you create symbolic formulas instead of anonymous functions.
syms x
if i==1
FUN(x) = Afun(x);
else
FUN(x) = Afun(x) + FUN(x);
end
where Afun might well be changing as you go. Then, at the end,
FUN_num = matlabFunction( simplify(FUN) );
to create FUN_num as the anonymous function that executes the formula numerically.
The creation of the formula will be a bit slower if you do this; the simplify() step in particular might take time, and should probably be skipped if you will only need to execute the handle a fairly moderate number of times. If the handle is going to be needed to execute a lot of times, then
FUN_num = matlabFunction( simplify(FUN), 'File', 'FUN_optimized.m', 'Optimize', true );
This will create a .m file in which the subexpressions of the functions are optimized to avoid redundant computations. This optimization can sometimes take quite a while (more than half an hour), but has the potential for higher performance... though not probably not for readability of the code!
  2 Commenti
Walter Roberson
Walter Roberson il 6 Dic 2017
Note: Your line
elseif 1 < i <= N - 2
will be interpreted as
elseif ((1 < i) <= (N - 2))
The first test, 1 < i, will return either 0 (false) or 1 (true). That 0 or 1 will then be compared to (N-2) in order to determine whether the condition is met.
MATLAB does not have any range-test operations. You should use
elseif 1 < i && i <= N - 2
Are Mjaavatten
Are Mjaavatten il 6 Dic 2017
First, thanks to Walter for a clarifying the logic of nesting inline functions. I made the following example to make sure I understood this correctly:
f = @(x) x(1)+x(2)
f = @(x) x(3)+x(4) + f(x)
f(1:4) gives 10, consistent with Walter's explanation.
Next, to Rasoul's problem. Why the nested functions do not work in your original code is not clear to me. But as Walter points out, this approach is probably not very efficient anyway. Instead, you might try this:
fun = @(x) g_fun(x,xmin,xmax,Nonlinear_curve,N)

Accedi per commentare.

Più risposte (1)

Are Mjaavatten
Are Mjaavatten il 5 Dic 2017
You are right that the problem lies with the line
FUN = @(x) Afun(x) + FUN(x);
This defines a recursive function, where FUN calls itself. This would lead to an infinite recursion since there is no specification on when to stop. My guess that recursion is not allowed in inline functions.
Anyway, there is a simpler way to achieve what I think you want:
function y = g_fun(x,xmin,xmax,curve,N)
x = [xmin;x(:);xmax]; % use x(:) to force column vector
y = 0;
for i = 2 : N+2
y = y +(x(i) - x(i - 1)) * (curve(x(i)) - curve(x(i - 1)))/2 ;
end
end
If your nonlinear_curve function is written in vector form, you can use the more compact form
function y = g_fun(x,xmin,xmax,curve,N)
x = [xmin;x(:);xmax]; % It may be simpler to define the whole x vector before calling g_fun
f = curve(x);
y = sum(diff(x).*diff(f)/2);
end
Here is an example of use:
N = 9;
x = linspace(pi*0.1,pi*0.9,N);
xmin = 0;xmax = pi;
Nonlinear_curve = @(x) sin(x);
y = g_fun(x,xmin,xmax,Nonlinear_curve,N);
disp(y)
  2 Commenti
Russell Grm
Russell Grm il 5 Dic 2017
First of all, I appreciate your follow-up to resolve my problem. However, I assume that my poor explanation of the issue might have caused a bit misunderstanding.
What I am trying to do is forming the objective function in which non of x values within the x vector are known. In other words, the output of the code written in my first comment should look like this:
fun = @(x) (1/2)* ((x(1) - xmin)* (Nonlinear_curve(x(1)) -
Nonlinear_curve(xmin)) + (x(2) - x(1))* (Nonlinear_curve(x(2)) -
Nonlinear_curve(x(1))) + (x(3) - x(2))* (Nonlinear_curve(x(3)) - Nonlinear_curve(x(2))));
So that I would be able to call it in the optimization as the function that its x vector is to be minimized.
Again your valuable comments are highly appreciated.
Walter Roberson
Walter Roberson il 6 Dic 2017
When FUN is a function handle,
FUN = @(x) Afun(x) + FUN(x);
does not define a recursive function. The above code is like
temp1 = Afun
temp2 = FUN;
FUN = @(x) temp1(x) + temp2(x);
When you examine a definition such as
FUN = @(x) Afun(x) + FUN(x);
it creates an anonymous function as follows:
  • an empty workspace, (call it W) is created
  • the defining string is examined
  • at each point where a variable is mentioned, if the variable is one of the variables listed in the @(x) portion, then the variable is replaced by an internal indicator that that relative position in the calling function parameters will be needed
  • at each point where a variable is mentioned other than one in the @() list, if the variable has not been mentioned before, then at the time of the definition, the usual variable hierarchy will be search to find the variable. If it is found then a copy of the value will be taken and placed inside the workspace being constructed, and the variable will be replaced with a reference to the anonymous function's workspace (W)
  • if the variable is not found in an appropriate enclosing context, then the variable will be replaced with a reference to an unresolved function handle, together with the context of where to start the search from
  • a variable that has been mentioned before will be replaced with the same thing it resolved to before
Then at execution time, each variable reference is satisfied either positionally from one of the anonymous function parameters, or from the copy of the variable in the anonymous function's workspace. Unresolved names will be searched for, but only as functions, never as variables. If a name was not resolved in the context of the definition and is not resolved at run time as a function name on the appropriate search path, then it will be considered undefined.
Note that this means that if you define a variable after you define the anonymous function, then the variable will not be found!
So looking back at
FUN = @(x) Afun(x) + FUN(x);
where FUN already exists as a function handle variable, then we can see that before the assignment on the left is done, the existing function handle variable FUN is copied into the workspace of the anonymous function being constructed, and the reference to FUN will refer to what is in that anonymous workspace. No change to FUN in the calling function after that point can change the content that was copied in -- imagine it being copied in as a pointer to the content, with the pointer being used at run time and the name only recorded for debugging use. Likewise, the anonymous function variable Afun will be copied in to the anonymous workspace.
Once the anonymous function workspace has been built and embedded as the Workspace property of the anonymous function object being constructed, the anonymous function object is assigned to FUN.
If FUN is invoked at that point, then execution of the anonymous function would involve pulling out the stored function handle variables from the workspace of the anonymous function and executing them. The stored value named FUN in the anonymous workspace was stored by content and does not refer to the FUN that now exists in the defining function's workspace, so there is no infinite recursion. There might be anonymous functions calling older versions of the anonymous functions through a number of layers of stored older versions until eventually you get to the original bare Afun(x) that was stored. This process is going to terminate. But, of course, with all those anonymous function layers, it might not exactly be fast!

Accedi per commentare.

Categorie

Scopri di più su Function Creation in Help Center e File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by