For two variable function, say f(x,y)=x^2+y+b, where b is:
b=raylrnd(1*sqrt(2/pi),10^6,1) %% b is 1x1000000 vector
and subject to the constraint that: 2*x+1<=b.
I want to find the maximum of the function for a interval say x is between [-10,10], and y is between [-10,10] (Off course, my actual function is more complete than this, I will need help to set up the framework so I can apply it to my actual function).
Is there a way to implement this?
Attempt:
Step 1: Write a file objfun.m.
function f = objfun(x,b)
f = x(1)^2+(2)+b;
Step 2: Write a file confuneq.m for the nonlinear constraints.
function [c, ceq] = confuneq(x)
% Nonlinear inequality constraints
c = 2*x(1)+1-b;
Step 3: Invoke constrained optimization routine.
for i=1:1:length(b)
bi=b(i);
x0 = [-1,1]; % Make a starting guess at the solution
options = optimoptions(#fmincon,'Algorithm','sqp');
[x,fval] = fmincon(#objfun,x0,[],[],[],[],[],[],...
#confuneq,options);
Related
I want to use MATLABs fmincon function to solve a non-linear problem of which I know that it can be solved in a different way very easily but I want to use fmincon (you might not need the following detailed information about the problem but I provided them in case you need):
Function f(x) is a quadratic function with its vertex at point (5|1).
f(x)=0.1(x-5)^2+1 for 0<=x<=5
Function g(x) is a polynom of order 4 with its vertex at Point (c|0).
g(x)=(x-c)^4 for 0<=x<=c
Function h is just a line on the x axis.
h=0 for c<=x<=5
I want to minimize the Area between the function f(x) and the two connected functions g(x) and h, in the interval [0,5]
minimize A=2*(int(f,[0,5])-int(g,[0,c]))=55/3 - (2*c^5)/5
Also I have the constraint that f(x) must always be 1 unit above the functions g(x) and h.
From the graph I know that the variable c must be between 0 and 2 (just a range for the fmincon function).
This is my .m file:
clc
clear
format long;
options = optimoptions(#fmincon, 'Display', 'iter', 'Algorithm', 'interior-point');
fun=#(x)55/3 - (2*(x(1))^5)/5;
lb = [0];
ub = [2];
[x,fval] = fmincon(fun,[0.1],[],[],[],[],lb,ub,#cons_Q6,options)
The constraints file looks like this (I inserted a lot of values for x with an increment of 0.1):
function [c,ceq]=cons_Q6(x)
c=[(0.0-x(1))^4-0.1*(0.0-5)^2
(0.1-x(1))^4-0.1*(0.1-5)^2
(0.2-x(1))^4-0.1*(0.2-5)^2
(0.3-x(1))^4-0.1*(0.3-5)^2
(0.4-x(1))^4-0.1*(0.4-5)^2
(0.5-x(1))^4-0.1*(0.5-5)^2
(0.6-x(1))^4-0.1*(0.6-5)^2
(0.7-x(1))^4-0.1*(0.7-5)^2
(0.8-x(1))^4-0.1*(0.8-5)^2
(0.9-x(1))^4-0.1*(0.9-5)^2
(1.0-x(1))^4-0.1*(1.0-5)^2
(1.1-x(1))^4-0.1*(1.1-5)^2
(1.2-x(1))^4-0.1*(1.2-5)^2
(1.3-x(1))^4-0.1*(1.3-5)^2
(1.4-x(1))^4-0.1*(1.4-5)^2
(1.5-x(1))^4-0.1*(1.5-5)^2
(1.6-x(1))^4-0.1*(1.6-5)^2
(1.7-x(1))^4-0.1*(1.7-5)^2
(1.8-x(1))^4-0.1*(1.8-5)^2
(1.9-x(1))^4-0.1*(1.9-5)^2
(2.0-x(1))^4-0.1*(2.0-5)^2
(2.1-x(1))^4-0.1*(2.1-5)^2
(2.2-x(1))^4-0.1*(2.2-5)^2
(2.3-x(1))^4-0.1*(2.3-5)^2
(2.4-x(1))^4-0.1*(2.4-5)^2
(2.5-x(1))^4-0.1*(2.5-5)^2
(2.6-x(1))^4-0.1*(2.6-5)^2
(2.7-x(1))^4-0.1*(2.7-5)^2
(2.8-x(1))^4-0.1*(2.8-5)^2
(2.9-x(1))^4-0.1*(2.9-5)^2
(3.0-x(1))^4-0.1*(3.0-5)^2
(3.1-x(1))^4-0.1*(3.1-5)^2
(3.2-x(1))^4-0.1*(3.2-5)^2
(3.3-x(1))^4-0.1*(3.3-5)^2
(3.4-x(1))^4-0.1*(3.4-5)^2
(3.5-x(1))^4-0.1*(3.5-5)^2
(3.6-x(1))^4-0.1*(3.6-5)^2
(3.7-x(1))^4-0.1*(3.7-5)^2
(3.8-x(1))^4-0.1*(3.8-5)^2
(3.9-x(1))^4-0.1*(3.9-5)^2
(4.0-x(1))^4-0.1*(4.0-5)^2
(4.1-x(1))^4-0.1*(4.1-5)^2
(4.2-x(1))^4-0.1*(4.2-5)^2
(4.3-x(1))^4-0.1*(4.3-5)^2
(4.4-x(1))^4-0.1*(4.4-5)^2
(4.5-x(1))^4-0.1*(4.5-5)^2
(4.6-x(1))^4-0.1*(4.6-5)^2
(4.7-x(1))^4-0.1*(4.7-5)^2
(4.8-x(1))^4-0.1*(4.8-5)^2
(4.9-x(1))^4-0.1*(4.9-5)^2
(5.0-x(1))^4-0.1*(5.0-5)^2
];
ceq=[];
As you can see, I've set the bounds for the unknown variable so that x(1)=[0,2] and I have set the constraints in the range [0,5] although I would only need them in the range of [0,2] because of the bounds for x(1).
Now, when I solve it like this I get a solution that doesn't fit all the constraints. But when I delete the unneccessary constraints in the range ]2;5]
function [c,ceq]=cons_Q6(x)
c=[(0.0-x(1))^4-0.1*(0.0-5)^2
(0.1-x(1))^4-0.1*(0.1-5)^2
(0.2-x(1))^4-0.1*(0.2-5)^2
(0.3-x(1))^4-0.1*(0.3-5)^2
(0.4-x(1))^4-0.1*(0.4-5)^2
(0.5-x(1))^4-0.1*(0.5-5)^2
(0.6-x(1))^4-0.1*(0.6-5)^2
(0.7-x(1))^4-0.1*(0.7-5)^2
(0.8-x(1))^4-0.1*(0.8-5)^2
(0.9-x(1))^4-0.1*(0.9-5)^2
(1.0-x(1))^4-0.1*(1.0-5)^2
(1.1-x(1))^4-0.1*(1.1-5)^2
(1.2-x(1))^4-0.1*(1.2-5)^2
(1.3-x(1))^4-0.1*(1.3-5)^2
(1.4-x(1))^4-0.1*(1.4-5)^2
(1.5-x(1))^4-0.1*(1.5-5)^2
(1.6-x(1))^4-0.1*(1.6-5)^2
(1.7-x(1))^4-0.1*(1.7-5)^2
(1.8-x(1))^4-0.1*(1.8-5)^2
(1.9-x(1))^4-0.1*(1.9-5)^2
(2.0-x(1))^4-0.1*(2.0-5)^2
];
ceq=[];
then I get the right result. Does anyone know why this happens and why MATLAB does not respect the constraints when I put them up for the whole range [0,5]?
-Your problem is more related to calculus than matlab tool
constraints like
function [c]=cons_Q6(x)
c=[x < 0; x > 0]; are just ignored by fmincon, because they are not logical
Technically you need to know the optimum c before solving
this optimization problem
- Another issue A = int(f,[0,5])-int(g,[0,c]) = 55/6 - c^5/5 instead of
A = 2*(int(f,[0,5])-int(g,[0,c])) = 55/3 - (2*c^5)/5
Factor 2 is used whether for even whether for odd function (like cosine or since).
Even for those kind of function the integration interval is reduced by half
I updated your optimization function and the solution c is as follow
x = [0, c], constraint is g(x)-f(x)-1<= 0--> (x-c)^4 -0.1(x-5)^2 <=0
x = [c, 5], constraint is h(x)-f(x)-1<= 0--> -0.1(x-5)^2 <=0
c must be predefined or guessed in advance, here I supposed c = 2
because your upper bound ub = 2
As a result
x = [0, 2], --> (x-c)^4 -0.1(x-5)^2 <=0
x = [2, 5], --> -0.1(x-5)^2 <=0
cons_Q6(x) is as follow
function [c,ceq]=cons_Q6(x)
c=[(0.0-x)^4-0.1*(0.0-5)^2;
(0.1-x)^4-0.1*(0.1-5)^2;
(0.2-x)^4-0.1*(0.2-5)^2;
(0.3-x)^4-0.1*(0.3-5)^2;
(0.4-x)^4-0.1*(0.4-5)^2;
(0.5-x)^4-0.1*(0.5-5)^2;
(0.6-x)^4-0.1*(0.6-5)^2;
(0.7-x)^4-0.1*(0.7-5)^2;
(0.8-x)^4-0.1*(0.8-5)^2;
(0.9-x)^4-0.1*(0.9-5)^2;
(1.0-x)^4-0.1*(1.0-5)^2;
(1.1-x)^4-0.1*(1.1-5)^2;
(1.2-x)^4-0.1*(1.2-5)^2;
(1.3-x)^4-0.1*(1.3-5)^2;
(1.4-x)^4-0.1*(1.4-5)^2;
(1.5-x)^4-0.1*(1.5-5)^2;
(1.6-x)^4-0.1*(1.6-5)^2;
(1.7-x)^4-0.1*(1.7-5)^2;
(1.8-x)^4-0.1*(1.8-5)^2;
(1.9-x)^4-0.1*(1.9-5)^2;
(2.0-x)^4-0.1*(2.0-5)^2;
-0.1*(2.1-5)^2;
-0.1*(2.2-5)^2;
-0.1*(2.3-5)^2;
-0.1*(2.4-5)^2;
-0.1*(2.5-5)^2;
-0.1*(2.6-5)^2;
-0.1*(2.7-5)^2;
-0.1*(2.8-5)^2;
-0.1*(2.9-5)^2;
-0.1*(3.0-5)^2;
-0.1*(3.1-5)^2;
-0.1*(3.2-5)^2;
-0.1*(3.3-5)^2;
-0.1*(3.4-5)^2;
-0.1*(3.5-5)^2;
-0.1*(3.6-5)^2;
-0.1*(3.7-5)^2;
-0.1*(3.8-5)^2;
-0.1*(3.9-5)^2;
-0.1*(4.0-5)^2;
-0.1*(4.1-5)^2;
-0.1*(4.2-5)^2;
-0.1*(4.3-5)^2;
-0.1*(4.4-5)^2;
-0.1*(4.5-5)^2;
-0.1*(4.6-5)^2;
-0.1*(4.7-5)^2;
-0.1*(4.8-5)^2;
-0.1*(4.9-5)^2;
-0.1*(5.0-5)^2;
];
ceq=[];
The constraints in the range ]2;5] are very necessary keep them
clc
clear
format long;
options = optimoptions(#fmincon, 'Display', 'iter', 'Algorithm',...
'interior-point');
fun=#(x)55/6 - (x^5)/5;
lb = [0];
ub = [2];
[c, A] = fmincon(fun,[0.1],[],[],[],[],lb,ub,#cons_Q6,options)
solution :
c = 1.257432726024430
A = 8.537951710969493
How do I solve the following system of equations on MATLAB when one of the elements of the variable vector is a constant? Please do give the code if possible.
More generally, if the solution is to use symbolic math, how will I go about generating large number of variables, say 12 (rather than just two) even before solving them?
For example, create a number of symbolic variables using syms, and then make the system of equations like below.
syms a1 a2
A = [matrix]
x = [1;a1;a2];
y = [1;0;0];
eqs = A*x == y
sol = solve(eqs,[a1, a2])
sol.a1
sol.a2
In case you have a system with many variables, you could define all the symbols using syms, and solve it like above.
You could also perform a parameter optimization with fminsearch. First you have to define a cost function, in a separate function file, in this example called cost_fcn.m.
function J = cost_fcn(p)
% make sure p is a vector
p = reshape(p, [length(p) 1]);
% system of equations, can be linear or nonlinear
A = magic(12); % your system, I took some arbitrary matrix
sol = A*p;
% the goal of the system of equations to reach, can be zero, or some other
% vector
goal = zeros(12,1);
% calculate the error
error = goal - sol;
% Use a cost criterion, e.g. sum of squares
J = sum(error.^2);
end
This cost function will contain your system of equations, and goal solution. This can be any kind of system. The vector p will contain the parameters that are being estimated, which will be optimized, starting from some initial guess. To do the optimization, you will have to create a script:
% initial guess, can be zeros, or some other starting point
p0 = zeros(12,1);
% do the parameter optimization
p = fminsearch(#cost_fcn, p0);
In this case p0 is the initial guess, which you provide to fminsearch. Then the values of this initial guess will be incremented, until a minimum to the cost function is found. When the parameter optimization is finished, p will contain the parameters that will result in the lowest error for your system of equations. It is however possible that this is a local minimum, if there is no exact solution to the problem.
Your system is over-constrained, meaning you have more equations than unknown, so you can't solve it. What you can do is find a least square solution, using mldivide. First re-arrange your equations so that you have all the constant terms on the right side of the equal sign, then use mldivide:
>> A = [0.0297 -1.7796; 2.2749 0.0297; 0.0297 2.2749]
A =
0.029700 -1.779600
2.274900 0.029700
0.029700 2.274900
>> b = [1-2.2749; -0.0297; 1.7796]
b =
-1.274900
-0.029700
1.779600
>> A\b
ans =
-0.022191
0.757299
I wanted to solve a constrained minimization problem using fmincon. But the constraints are defined in terms of a function like f(x_0)<a, where x_0 is a solution to the problem. Is it possible?
On the docs, the example only include this x_0<a form.
Code:
f_obj = #(x)var_zcors(x,t_cw);
opt_theta = fminbnd(f_obj,0,360);
Now, x should constrained such that f_constraint(x)< a.
Update(From answer by #Phil Goddard):
f_obj = #(x)var_zcors(x,t_cw);
f_nl = #(x)deal(f_constraint(x)-a,[]);
x0 = 180; % or whatever is appropriate
opt_theta = fmincon(f_obj,x0,[],[],[],[],0,360,f_nl);
Say in the above code f_constraint returns a vector [x_min y_max] instead of a scalar. And I want to specify the following constraints:
x_min>b
y_max<a
What is a possible way to achieve that?
You have a nonlinear constraint and hence need to use the nonlinear constraint input to fmincon. That is,
f_obj = #(x)var_zcors(x,t_cw);
f_nl = #(x)deal(f_constraint(x)-a,[]);
x0 = 180; % or whatever is appropriate
opt_theta = fmincon(f_obj,x0,[],[],[],[],0,360,f_nl);
If you have multiple (non-linear) constraints, then as per the examples in the doc, you write a function to return a vector of constraints. In your case you want to write a function in a separate file like the following:
function [c,ceq] = my_nonlinear_constraints(x,ab)
% define the non-linear inequality constraints
% (This assumes that ab is a 2 element vector containing your a and b
% variables.)
[x_min,y_max] = f_constraint(x);
c = nan(2,1);
c(1) = -x_min+ab(2); % this is x_min>b
c(2) = y_max-ab(1); % this is y_max<a
% There are no non-linear equality constraints, but this is required
ceq = [];
Then, to perform the optimization, you want
% Variables a and b must be defined prior to this.
f_obj = #(x)var_zcors(x,t_cw);
f_nl = #(x)my_nonlinear_constraints(x,[a b]);
x0 = 180; % or whatever is appropriate
opt_theta = fmincon(f_obj,x0,[],[],[],[],0,360,f_nl);
I have an integrated error expression E = int[ abs(x-p)^2 ]dx with limits x|0 to x|L. The variable p is a polynomial of the form 2*(a*sin(x)+b(a)*sin(2*x)+c(a)*sin(3*x)). In other words, both coefficients b and c are known expressions of a. An additional equation is given as dE/da = 0. If the upper limit L is defined, the system of equations is closed and I can solve for a, giving the three coefficients.
I managed to get an optimization routine to solve for a purely based on maximizing L. This is confirmed by setting optimize=0 in the code below. It gives the same solution as if I solved the problem analytically. Therefore, I know the equations to solve for the coefficent a are correct.
I know the example I presented can be solved with pencil and paper, but I'm trying to build an optimization function that is generalized for this type of problem (I have a lot to evaluate). Ideally, polynomial is given as an input argument to a function which then outputs xsol. Obviously, I need to get the optimization to work for the polynomial I presented here before I can worry about generalizations.
Anyway, I now need to further optimize the problem with some constraints. To start, L is chosen. This allows me to calculate a. Once a is know, the polynomial is a known function of x only i.e p(x). I need to then determine the largest INTERVAL from 0->x over which the following constraint is satisfied: |dp(x)/dx - 1| < tol. This gives me a measure of the performance of the polynomial with the coefficient a. The interval is what I call the "bandwidth". I would like to emphasis two things: 1) The "bandwidth" is NOT the same as L. 2) All values of x within the "bandwidth" must meet the constraint. The function dp(x)/dx does oscillate in and out of the tolerance criteria, so testing the criteria for a single value of x does not work. It must be tested over an interval. The first instance of violation defines the bandwidth. I need to maximize this "bandwidth"/interval. For output, I also need to know which L lead to such an optimization, hence I know the correct a to choose for the given constraints. That is the formal problem statement. (I hope I got it right this time)
Now my problem is setting this whole thing up with MATLAB's optimization tools. I tried to follow ideas from the following articles:
Tutorial for the Optimization Toolbox™
Setting optimize=1 for the if statement will work with the constrained optimization. I thought some how nested optimization is involved, but I couldn't get anything to work. I provided known solutions to the problem from the IMSL optimization library to compare/check with. They are written below the optimization routine. Anyway, here is the code I've put together so far:
function [history] = testing()
% History
history.fval = [];
history.x = [];
history.a = [];
%----------------
% Equations
polynomial = #(x,a) 2*sin(x)*a + 2*sin(2*x)*(9/20 -(4*a)/5) + 2*sin(3*x)*(a/5 - 2/15);
dpdx = #(x,a) 2*cos(x)*a + 4*cos(2*x)*(9/20 -(4*a)/5) + 6*cos(3*x)*(a/5 - 2/15);
% Upper limit of integration
IC = 0.8; % initial
LB = 0; % lower
UB = pi/2; % upper
% Optimization
tol = 0.003;
% Coefficient
% --------------------------------------------------------------------------------------------
dpda = #(x,a) 2*sin(x) + 2*sin(2*x)*(-4/5) + 2*sin(3*x)*1/5;
dEda = #(L,a) -2*integral(#(x) (x-polynomial(x,a)).*dpda(x,a),0,L);
a_of_L = #(L) fzero(#(a)dEda(L,a),0); % Calculate the value of "a" for a given "L"
EXITFLAG = #(L) get_outputs(#()a_of_L(L),3); % Be sure a zero is actually calculated
% NL Constraints
% --------------------------------------------------------------------------------------------
% Equality constraint (No inequality constraints for parent optimization)
ceq = #(L) EXITFLAG(L) - 1; % Just make sure fzero finds unique solution
confun = #(L) deal([],ceq(L));
% Objective function
% --------------------------------------------------------------------------------------------
% (Set optimize=0 to test coefficent equations and proper maximization of L )
optimize = 1;
if optimize
%%%% Plug in solution below
else
% Optimization options
options = optimset('Algorithm','interior-point','Display','iter','MaxIter',500,'OutputFcn',#outfun);
% Optimize objective
objective = #(L) -L;
xsol = fmincon(objective,IC,[],[],[],[],LB,UB,confun,options);
% Known optimized solution from IMSL library
% a = 0.799266;
% lim = pi/2;
disp(['IMSL coeff (a): 0.799266 Upper bound (L): ',num2str(pi/2)])
disp(['code coeff (a): ',num2str(history.a(end)),' Upper bound: ',num2str(xsol)])
end
% http://stackoverflow.com/questions/7921133/anonymous-functions-calling-functions-with-multiple-output-forms
function varargout = get_outputs(fn, ixsOutputs)
output_cell = cell(1,max(ixsOutputs));
[output_cell{:}] = (fn());
varargout = output_cell(ixsOutputs);
end
function stop = outfun(x,optimValues,state)
stop = false;
switch state
case 'init'
case 'iter'
% Concatenate current point and objective function
% value with history. x must be a row vector.
history.fval = [history.fval; optimValues.fval];
history.x = [history.x; x(1)];
history.a = [history.a; a_of_L(x(1))];
case 'done'
otherwise
end
end
end
I could really use some help setting up the constrained optimization. I'm not only new to optimizations, I've never used MATLAB to do so. I should also note that what I have above does not work and is incorrect for the constrained optimization.
UPDATE: I added a for loop in the section if optimizeto show what I'm trying to achieve with the optimization. Obviously, I could just use this, but it seems very inefficient, especially if I increase the resolution of range and have to run this optimization many times. If you uncomment the plots, it will show how the bandwidth behaves. By looping over the full range, I'm basically testing every L but surely there's got to be a more efficient way to do this??
UPDATE: Solved
So it seems fmincon is not the only tool for this job. In fact I couldn't even get it to work. Below, fmincon gets "stuck" on the IC and refuses to do anything...why...that's for a different post! Using the same layout and formulation, fminbnd finds the correct solution. The only difference, as far as I know, is that the former was using a conditional. But my conditional is nothing fancy, and really unneeded. So it's got to have something to do with the algorithm. I guess that's what you get when using a "black box". Anyway, after a long, drawn out, painful, learning experience, here is a solution:
options = optimset('Display','iter','MaxIter',500,'OutputFcn',#outfun);
% Conditional
index = #(L) min(find(abs([dpdx(range(range<=L),a_of_L(L)),inf] - 1) - tol > 0,1,'first'),length(range));
% Optimize
%xsol = fmincon(#(L) -range(index(L)),IC,[],[],[],[],LB,UB,confun,options);
xsol = fminbnd(#(L) -range(index(L)),LB,UB,options);
I would like to especially thank #AndrasDeak for all their support. I wouldn't have figured it out without the assistance!
Is is it possible to use an ODE solver, such as ode45, and still be able to 'change' values for the parameters within the called function?
For example, if I were to use the following function:
function y = thisode(t, Ic)
% example derivative function
% parameters
a = .05;
b = .005;
c = .0005;
d = .00005;
% state variables
R = Ic(1);
T = Ic(2);
y = [(R*a)-(T/b)+d; (d*R)-(c*T)];
with this script:
clear all
% Initial conditions
It = [0.06 0.010];
% time steps
time = 0:.5:10;
% ODE solver
[t,Ic1] = ode45(#thisode, time, It);
everything works as I would expect. However, I would like a way to easily change the parameter values, but still run multiple iterations of the ODE solver with just one function and one script. However, it does not seem like I can just add more terms to the ODE solver, for example:
function y = thisode(t, Ic, P)
% parameters
a = P(1);
b = P(2);
c = P(3);
d = P(4);
% state variables
R = Ic(1);
T = Ic(2);
y = [(R*a)-(T/b)+d; (d*R)-(c*T)];
with this script:
clear all
% Initial conditions
It = [0.06 0.010];
P1 = [.05 .005 .0005 .00005]
% time steps
time = 0:.5:10;
% ODE solver
[t,Ic1] = ode45(#thisode, time, It, [], P1);
does not work. I guess I know this shouldn't work, but I have been unable to come up with a solution. I was also considering an if statement within the function and then hard coding several sets of parameters based to be used (e.g use set 1 when P == 1, set 2 when P == 2, etc) but this also did not work as I don't where to call the set to be used with an ODE. Any tips or suggestion on how to use one function and one script with an ODE solver while being able to change parameter values would be much appreciated.
Thank you,
Mike
You'll have to call the function differently:
[t,Ic1] = ode45(#(t,y) thisode(t,y,P1), time, It);
The function ode45 assumes all functions passed to it accept only an t and a y. The above call is a standard trick to get Matlab to pass P1, while ode45 will pass it t and y on every call.