Put indices inside fmincon function in Matlab - matlab

I have a problem in using fmincon in Matlab when the variables are using various indices instead of fixed indices. In brief, I have Matlab code as below example:
x = fmincon(objfun,x0,A,b,Aeq,beq,lb,ub)
function f = objfun(x)
f = a(1,1)*((1 - x(1))*(b(1) + c(1)) + a(2,1)*((1 - x(2))*(b(2) + c(1))
+ a(1,2)*((1 - x(1))*(b(1) + c(2)) + a(2,2)*((1 - x(2))*(b(2) + c(2))
end
In this case, I want to make a general equation for f as follows:
f = a(i,j)*((1 - x(i))*(b(i) + c(j))
What do I need to add to f function to realize the same result as the first f formula?

Related

Solving optimal control problems, ode45 vs fmincon

Good afternoon!
First things first, I looked for similar questions for a while, but (probably because of my inexperience) I've found nothing similar to what I'm going to ask.
I'm using matlab for the first time to solve this kind of problems, so I'm not sure of what to do. A brief explenation:
I'm doing a project for my Optimal Control course: I have to replicate the results of a paper about employment, and I'm stuck with the plots. I have the following data:
five variable functions (U(t), T(t), R(t), V1(t) and V2(t))
four control functions(u1(t), u2(t), u3(t), u4(t))
constraints on the control variables (each u must be between 0 and 1)
initial values for U, T, R, V1 and V2 (in t=0, in particular V1 and V2 are constant over time)
final values for the λ coefficients in the hamiltonian
(note: for the controls, I've already found the optimal expression, which is in this form: ui = min{1, max{0,"expression"}}. If needed, I can give also the four expressions, neglected to
synthesize a little)
Under professor's suggestions, I've tried to use fmincon, that theoretically should give me directly the information that I need to plot some result using only the cost function of the problem. But in this case I have some issues involving time in the calculations. Below, the code that I used for fmincon:
syms u
%note: u(5) corresponds to U(t), but this is the only way I've found to get
%a result, the other u(i) are in ascending order (u(1) = u1 and so on...)
g = #(u) 30*u(5) + (20/2)*(u(1))^2 + (20/2)*(u(2))^2 + (10/2)*(u(3))^2 + (40/2)*(u(4))^2;
%initial guesses
u0 = [0 0 0 0 100000]; %
A = [];
b = [];
Aeq = [];
beq = [];
lb = 0.0 * ones(1,2,3,4);
ub = 1.0 * ones(1,2,3,4);
[x,fval,output,lambda] = fmincon(g, u0, A, b, Aeq, beq, lb, ub);
Whit this code, i get (obviously) only one value for each variable as result, and since I've not found any method to involve time, as I said before, I start looking for other solving strategies.
I found that ode45 is a differential equation solver that has the "time iteration" already included in the algorithm, so I tried to write the code to get it work with my problem.
I took all the equations from the paper and put them in a vector as shown in the mathworks examples, and this is my matlab file:
syms u1(t) u2(t) u3(t) u4(t)
syms U(t) T(t) R(t) V1(t) V2(t)
syms lambda_u lambda_t lambda_r lambda_v1 lambda_v2
%all the parameters provided by the paper
delta = 500;
alpha1 = 0.004;
alpha2 = 0.005;
alpha3 = 0.006;
gamma1 = 0.001;
gamma2 = 0.002;
phi1 = 0.22;
phi2 = 0.20;
delta1 = 0.09;
delta2 = 0.05;
k1 = 0.000003;
k2 = 0.000002;
k3 = 0.0000045;
%these two variable are set constant
V1 = 200;
V2 = 100;
%weight values for the cost function (only A1 is used in this case, but I left them all since the unused ones are irrelevant)
A1 = 30;
A2 = 20;
A3 = 20;
A4 = 10;
A5 = 40;
%ordering the unknowns in an array
x = [U T R u1 u2 u3 u4];
%initial conditions, ordered as the x vector (for the ui are guesses)
y0 = [100000 2000 1000 0 0 0 0];
%system set up
f = #(t,x) [delta - (1 + x(4))*k1*x(1)*V1 - (1 + x(5))*k2*x(1)*V2 - alpha1*x(1) + gamma1*x(2) + gamma2*x(3);...
(1 + x(4))*k1*x(1)*V1 - k3*x(2)*V2 - alpha2*x(2) - gamma1*x(2);...
(1 + x(5))*k2*x(1)*V2 - alpha3*x(3) - gamma2*x(3) + k3*x(2)*V2;...
alpha2*x(2) + gamma1*x(2) + (1 + x(6))*phi1*x(1) + k3*x(2)*V2 - delta1*V1;...
alpha3*x(3) + gamma2*x(3) + (1 + x(7))*phi2*x(1) - delta2*V2;...
-A1 + (1 + x(4))*k1*V1*(lambda_u - lambda_t) + (1 + x(5))*k2*V2*(lambda_u - lambda_r) + lambda_u*alpha1 - lambda_v1*(1 + x(6))*phi1 - lambda_v2*(1 + x(7))*phi2;...
-lambda_u*gamma1 + (alpha2 + gamma1)*(lambda_t - lambda_v1) + k3*V2*(lambda_t - lambda_r - lambda_v1);...
-lambda_u*gamma2 + (alpha3 + gamma2)*(lambda_r - lambda_v2);...
(1 + x(4))*k1*x(1)*(lambda_u - lambda_t) + lambda_v1*delta1;...
(1 + x(5))*k2*x(1)*(lambda_u -lambda_r) + k3*x(2)*(lambda_t - lambda_r - lambda_v1) + lambda_v2*delta2];
%using ode45 to solve over the chosen time interval
[t,xa] = ode45(f,[0 10],y0);
With this code, I get the following error:
Error using odearguments (line 95)
#(T,X)[DELTA-(1+X(4))*K1*X(1)*V1-(1+X(5))*K2*X(1)*V2-ALPHA1*X(1)+GAMMA1*X(2)+GAMMA2*X(3);(1+X(4))*K1*X(1)*V1-K3*X(2)*V2-ALPHA2*X(2)-GAMMA1*X(2);(1+X(5))*K2*X(1)*V2-ALPHA3*X(3)-GAMMA2*X(3)+K3*X(2)*V2;ALPHA2*X(2)+GAMMA1*X(2)+(1+X(6))*PHI1*X(1)+K3*X(2)*V2-DELTA1*V1;ALPHA3*X(3)+GAMMA2*X(3)+(1+X(7))*PHI2*X(1)-DELTA2*V2;-A1+(1+X(4))*K1*V1*(LAMBDA_U-LAMBDA_T)+(1+X(5))*K2*V2*(LAMBDA_U-LAMBDA_R)+LAMBDA_U*ALPHA1-LAMBDA_V1*(1+X(6))*PHI1-LAMBDA_V2*(1+X(7))*PHI2;-LAMBDA_U*GAMMA1+(ALPHA2+GAMMA1)*(LAMBDA_T-LAMBDA_V1)+K3*V2*(LAMBDA_T-LAMBDA_R-LAMBDA_V1);-LAMBDA_U*GAMMA2+(ALPHA3+GAMMA2)*(LAMBDA_R-LAMBDA_V2);(1+X(4))*K1*X(1)*(LAMBDA_U-LAMBDA_T)+LAMBDA_V1*DELTA1;(1+X(5))*K2*X(1)*(LAMBDA_U-LAMBDA_R)+K3*X(2)*(LAMBDA_T-LAMBDA_R-LAMBDA_V1)+LAMBDA_V2*DELTA2]
returns a vector of length 10, but the length of initial conditions vector is 7. The vector returned by
#(T,X)[DELTA-(1+X(4))*K1*X(1)*V1-(1+X(5))*K2*X(1)*V2-ALPHA1*X(1)+GAMMA1*X(2)+GAMMA2*X(3);(1+X(4))*K1*X(1)*V1-K3*X(2)*V2-ALPHA2*X(2)-GAMMA1*X(2);(1+X(5))*K2*X(1)*V2-ALPHA3*X(3)-GAMMA2*X(3)+K3*X(2)*V2;ALPHA2*X(2)+GAMMA1*X(2)+(1+X(6))*PHI1*X(1)+K3*X(2)*V2-DELTA1*V1;ALPHA3*X(3)+GAMMA2*X(3)+(1+X(7))*PHI2*X(1)-DELTA2*V2;-A1+(1+X(4))*K1*V1*(LAMBDA_U-LAMBDA_T)+(1+X(5))*K2*V2*(LAMBDA_U-LAMBDA_R)+LAMBDA_U*ALPHA1-LAMBDA_V1*(1+X(6))*PHI1-LAMBDA_V2*(1+X(7))*PHI2;-LAMBDA_U*GAMMA1+(ALPHA2+GAMMA1)*(LAMBDA_T-LAMBDA_V1)+K3*V2*(LAMBDA_T-LAMBDA_R-LAMBDA_V1);-LAMBDA_U*GAMMA2+(ALPHA3+GAMMA2)*(LAMBDA_R-LAMBDA_V2);(1+X(4))*K1*X(1)*(LAMBDA_U-LAMBDA_T)+LAMBDA_V1*DELTA1;(1+X(5))*K2*X(1)*(LAMBDA_U-LAMBDA_R)+K3*X(2)*(LAMBDA_T-LAMBDA_R-LAMBDA_V1)+LAMBDA_V2*DELTA2]
and the initial conditions vector must have the same number of elements.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Error in test (line 62)
[t,xa] = ode45(f,[0 10],y0);
For which I can't find a solution, since I have used all the initial values given in the paper. The only values that I have left are the final values for the lambda coefficients, since they are final values, and I am not sure if they can be used.
In this case, I can't also understand where I should put the bounds on the control variable.
For completeness, I will provide also the link to the paper in question:
https://www.ripublication.com/ijss17/ijssv12n3_13.pdf
Can you help me figure out what I can do to solve my problems?
P.S: I know this is a pretty bad code, but I'm basing on the basics tutorials on mathworks; for sure this should need to be refactored and ordered in various file (one for the cost function and one for the constraints for example) but firstly I would like to understand where the problem is and then I will put all in a pretty form.
Thank you so much!
Generally you confused something with Vectors. In initial conditions you declared 7 values:
%initial conditions, ordered as the x vector (for the ui are guesses)
y0 = [100000 2000 1000 0 0 0 0];
But you declared 10 ODE's:
%system set up
f = #(t,x) [delta - (1 + x(4))*k1*x(1)*V1 - (1 + x(5))*k2*x(1)*V2 - alpha1*x(1) + gamma1*x(2) + gamma2*x(3);...
(1 + x(4))*k1*x(1)*V1 - k3*x(2)*V2 - alpha2*x(2) - gamma1*x(2);...
(1 + x(5))*k2*x(1)*V2 - alpha3*x(3) - gamma2*x(3) + k3*x(2)*V2;...
alpha2*x(2) + gamma1*x(2) + (1 + x(6))*phi1*x(1) + k3*x(2)*V2 - delta1*V1;...
alpha3*x(3) + gamma2*x(3) + (1 + x(7))*phi2*x(1) - delta2*V2;...
-A1 + (1 + x(4))*k1*V1*(lambda_u - lambda_t) + (1 + x(5))*k2*V2*(lambda_u - lambda_r) + lambda_u*alpha1 - lambda_v1*(1 + x(6))*phi1 - lambda_v2*(1 + x(7))*phi2;...
-lambda_u*gamma1 + (alpha2 + gamma1)*(lambda_t - lambda_v1) + k3*V2*(lambda_t - lambda_r - lambda_v1);...
-lambda_u*gamma2 + (alpha3 + gamma2)*(lambda_r - lambda_v2);...
(1 + x(4))*k1*x(1)*(lambda_u - lambda_t) + lambda_v1*delta1;...
(1 + x(5))*k2*x(1)*(lambda_u -lambda_r) + k3*x(2)*(lambda_t - lambda_r - lambda_v1) + lambda_v2*delta2];
Every line in above code is recognized as one ODE.
But that's not all. The second problem is with your construction. You mixed symbolic math (lambda declared as syms) with numerical solving, which will be tricky. I'm not familiar with the exact scientific problem you are trying to solve, but if you can't avoid symbolic math, maybe you should try dsolve from Symbolic Math Toolbox?

Using Matlab's Solve() with Symbolic Constants

I'm have a system of two questions with two unknown variables that I'm trying to use Matlab's solve() function to solve, but hitting errors that are almost surely on my end. I'm trying to solve The following two equations where r, lambda, and X are constants. To do so, I've been trying to run the following:
clear all;
syms VA VB r X L;
assumeAlso(VB <= VA);
assumeAlso(0 <= VB);
assumeAlso(0 < r <= 1);
assumeAlso(0 < L);
assumeAlso(0 < X);
assumeAlso(VA, 'real');
assumeAlso(VB, 'real');
assumeAlso(r, 'real');
assumeAlso(L, 'real');
assumeAlso(X, 'real');
eqns = [VA == ((r*VA + L*(VA-VB))^2)/(2*X*(r+2*L)) + (L*(VA+VB)*(r*VA+L*(VA-VB)))/(X*(r+2*L)) + ...
(((r^2/L+r)*VA + r*VB)^2 - (r*VA+L*(VA-VB))^2)/(2*X*(r+L)) + ...
(L*VB*((r+L)*VB - L*VA + r^2/L*VA))/(X*(r+L)) + ...
(X/(2*r)) - (((r^2/L+r)*VA+r*VB)^2)/(2*X*r) - VA*(1-1/X*((r^2/L+r)*VA+r*VB)), ...
...
VB == (L^2*VA^2 - L^2*VB^2 + r*VA*(L*VA+L*VB))/(X*(r+2*L)) + ...
(L*VA*(r^2/L*VA + r*VB - L*(VA-VB)))/(X*(r+L)) + ...
(VA*(X-((r^2/L+r)*VA + r*VB)))/X];
S = solve(eqns,[VA VB])
My goal is to solve for VA and VB in terms of r, X, and L, which seems like it should be possible. When I fill in values for r, L and X I am easily able to obtain a solution.
When I run this code, however, I get the message:
Warning: Explicit solution could not be found.
which normally I would interpret to mean that there is in fact no solution, but when I run
S = solve(eqns)
I do not get the same output, but:
(solvelib::cartesianPower(R_, 2) minus solvelib::VectorImageSet(matrix([[z], [0]]), z, C_)) intersect solvelib::VectorImageSet(matrix([[-(VA^4*x^5 - 2*L^5*VA*VB^3 - 2*L^5*VA^3*VB - L*VA^4*x^4 - 3*L^4*VA^4*x + L^4*VB^4*x + 4*L^5*VA^2*VB^2 - 5*L^2*VA^4*x^3 + 4*L^3*VA^4*x^2 + L^3*VB^4*x^2 + 4*L^2*VA^2*VB^2*x^3 - 5*L^3*VA^2*VB^2*x^2 + 4*L*VA^3*VB*x^4 + L^4*VA*VB^3*x + 9*L^4*VA^3*VB*x + L*VA^2*VB^2*x^4 + 2*L^2*VA*VB^3*x^3 + 2*L^3*VA*VB^3*x^2 - 8*L^3*VA^3*VB*x^2 - 8*L^4*VA^2*VB^2*x)/(L^4*VA^3 - L^4*VB^3 - L^4*VA*VB^2 + L^4*VA^2*VB)], [x]]), x, R_ intersect RootOf(z^6 + (z^5*(L*VA^4 + L*VA^2*VB^2 + 4*L*VA^3*VB))/VA^4 + (z^4*(- 7*L^2*VA^4 + 2*L^2*VA*VB^3 + 8*L^2*VA^3*VB + 6*L^2*VA^2*VB^2))/VA^4 + (z^3*(- 5*L^3*VA^4 + L^3*VB^4 + 6*L^3*VA*VB^3 - 6*L^3*VA^3*VB + 4*L^3*VA^2*VB^2))/VA^4 + (z^2*(7*L^4*VA^4 + 3*L^4*VB^4 + 6*L^4*VA*VB^3 - 2*L^4*VA^3*VB - 14*L^4*VA^2*VB^2))/VA^4 - (z*(6*L^5*VA^4 - 2*L^5*VB^4 - 16*L^5*VA^3*VB + 12*L^5*VA^2*VB^2))/VA^4 + (L^6*VA^4 + L^6*VB^4 - 4*L^6*VA*VB^3 - 4*L^6*VA^3*VB + 6*L^6*VA^2*VB^2)/VA^4, z)) intersect solvelib::VectorImageSet(matrix([[x], [y]]), [x, y], [Dom::Interval(0, Inf), Dom::Interval(0, [1])])
which does not have a solution for VA and VB.
Does anyone have an idea how I can get matlab's solve() to solve for [VA VB] in terms of r, L, and X?
Thank you!
Try using the ReturnConditions flag of the solve command. As in,
S = solve(eqns,[VA,VB],'ReturnConditions',true)
This will return a struct containing an array of solutions and required conditions for each.
I played around a bit with your example and hit the same roadblocks as you when making the same assumptions. If we start from zero assumptions, solve will find a set of solutions for the given equations. You could inspect the conditions for each of the given solutions and see what if any meet your original constraints?
The example given above yields results as long as VA and VB are not constrained to the Reals. Could there be a typo somewhere in your system of eqns?

Series expansion of a function about infinity - how to return coefficients of series as a Matlab array?

This question is connected to this one. Suppose again the following code:
syms x
f = 1/(x^2+4*x+9)
Now taylor allows the function f to be expanded about infinity:
ts = taylor(f,x,inf,'Order',100)
But the following code
c = coeffs(ts)
produces errors, because the series does not contain positive powers of x (it contains negative powers of x).
In such a case, what code should be used?
Since the Taylor Expansion around infinity was likely performed with the substitution y = 1/x and expanded around 0, I would explicitly make that substitution to make the power positive for use on coeffs:
syms x y
f = 1/(x^2+4x+9);
ts = taylor(f,x,inf,'Order',100);
[c,ty] = coeffs(subs(ts,x,1/y),y);
tx = subs(ty,y,1/x);
The output from taylor is not a multivariate polynomial, so coeffs won't work in this case. One thing you can try is using collect (you may get the same or similar result from using simplify):
syms x
f = 1/(x^2 + 4*x + 9);
ts = series(f,x,Inf,'Order',5) % 4-th order Puiseux series of f about 0
c = collect(ts)
which returns
ts =
1/x^2 - 4/x^3 + 7/x^4 + 8/x^5 - 95/x^6
c =
(x^4 - 4*x^3 + 7*x^2 + 8*x - 95)/x^6
Then you can use numden to extract the numerator and denominator from either c or ts:
[n,d] = numden(ts)
which returns the following polynomials:
n =
x^4 - 4*x^3 + 7*x^2 + 8*x - 95
d =
x^6
coeffs can then be used on the numerator. You may find other functions listed here helpful as well.

Is this function handle too long for MATLAB to integrate?

I have written the following code in order to try to plot the following integral against values of r, but MATLAB gives me an error -- is fun too long? am I going wrong somewhere else?
figure(1); %f_1
r = 0:0.001:50;
q = zeros(1, size(r));
for m = 1:numel(r)
fun = #(t) ((-3*(r(m).^3)*sin(3*t) + 2*(r(m)^2)*cos(2*t) + 7*r(m)*cos(t) -2*sin(t))*(-6*(r(m)^3)*sin(3*t) + 2*(r(m)^3)*cos(3*t) - 3*(r(m)^4)*cos(4*t) - 2*(r(m)^3)*sin(3*t) + 2*(r(m)^2)*cos(2*t) + 7*(r(m)^2)*sin(2*t))) - ((3*(r(m).^3).*cos(3*t) + 2*(r(m).^2).*sin(2*t) + 7*r(m).*sin(t) - 2*r(m).*cos(t))*(-6*(r(m).^3).*cos(3*t) + 2*(r(m).^3).*sin(3*t) + 3*(r(m).^4).*sin(4*t) - 2* (r(m).^3).*cos(3*t) - 2*(r(m).^2).*sin(2*t) + 7*(r(m).^2).*cos(2*t)))./((-3*(r(m).^3).*sin(3.*t) + 2*(r(m).^2)*cos(2.*t) + 7*r(m).*cos(t) - 2*sin(t)).^2 + (3*(r(m).^3).*cos(3*t) + 2*(r(m).^2).*sin(2*t) + 7*r(m).*sin(t) - 2*r(m).*cos(t)).^2);
q(m) = quad(fun, 0, 2*pi);
end
The error I get is
Error using * Inner matrix dimensions must agree.
Error in #(t)......
Error in quad (line 76) y = f(x, varargin{:});
I'll show you a way you may proceed, based on a retained r and fun (I did not pick all the terms of the native function):
r = 0:0.1:50;
q = zeros(size(r));
for ii = 1:numel(r)
fun = #(t) (-3.*(r(ii).^3).*sin(3.*t) + 2.*(r(ii).^2).*cos(2.*t) + 7.*r(ii).*cos(t) -2.*sin(t));
q(ii) = quad(fun,0,2.*pi);
end
Since your r is quite huge (50001 elements if I remember right), I'd go for parfor insted of simple for loop, too.
EDIT
As alternative solution, you could achieve the same results without any anonymous function, by following this way:
r = 0:.01:50;
fun1 = zeros(size(r));
t = 0:.001:(2*pi);
for ii = 1:numel(r)
fun1(ii) = trapz(t,(-3.*(r(ii).^3).*sin(3.*t) + 2.*(r(ii).^2).*cos(2.*t) + 7.*r(ii).*cos(t) -2.*sin(t)));
end

Matlab: How to solve the system of nonlinear equations with additional parameters?

I would like to create a function that finds the parameters p and q of Bass diffusion model, given the data of two time periods.
The model (equation) is the following:
n(T) = p*m + (q-p)*n(T-1) + q/m*n(T-1)^2
where
n(T) = number of addoptions occuring in period T
n(T-1) = number of cumulative adoptions that occured before T
p = coefficient of innovation
q = coefficient of imitation
m = number of eventual adopters
for example if m = 3.000.000
and the data for the years below is the following:
2000: n(T) = 820, n(T-1) = 0
2005: n(T) = 25000, n(T-1) = 18000
then the following equation system has to be solved (in order to determine the values of p and q):
p*m + (q-p)*0 + q/3.000.000 * 0^2 == 820
p*m + (q-p)*18000 + q/3.000.000 * 18000^2 == 25000
By following Matlab documentation I tried to create a function Bass:
function F = Bass(m, p, q, cummulativeAdoptersBefore)
F = [p*m + (q-p)*cummulativeAdoptersBefore(1) + q/m*cummulativeAdoptersBefore(1).^2;
p*m + (q-p)*cummulativeAdoptersBefore(2) + q/m*cummulativeAdoptersBefore(2).^2];
end
Which should be used in fsolve(#Bass,x0,options) but in this case m, p, q, cummulativeAdoptersBefore(1), and cummulativeAdoptersBefore(2) should be given in x0 and all variables would be considered as unknown instead of just the latter two.
Does anyone know how to solve the system of equations such as above?
Thank you!
fsolve() seeks to minimize the function you supply as argument. Thus, you have to change your equations to
p*m + (q-p)*0 + q/3.000.000 * 0^2 - 820 == 0
p*m + (q-p)*18000 + q/3.000.000 * 18000^2 - 25000 == 0
and in Matlab syntax
function F = Bass(m, p, q, cumulativeAdoptersBefore, cumulativeAdoptersAfter)
F = [p*m + (q-p)*cumulativeAdoptersBefore(1) ...
+ q/m *cumulativeAdoptersBefore(1).^2
- cumulativeAdoptersAfter(1);
p*m + (q-p)*cumulativeAdoptersBefore(2) ...
+ q/m *cumulativeAdoptersBefore(2).^2
- cumulativeAdoptersAfter(2)];
end
Note: There is a typo in your Bass function (multiplication instead of sum).
Now you have a function, which takes more parameters than there are unkowns.
One option is to create an anonymous function, which only takes the unknowns as arguments and to fix the other parameters via a closure.
To fit the unkowns p and q, you could use something like
cumulativeAdoptersBefore = [0, 1800];
cumulativeAdoptersAfter = [820, 25000];
m = 3e6;
x = [0, 0]; %# Probably, this is no good starting guess.
xopt = fsolve(#(x) Bass(m, x(1), x(2), cumulativeAdoptersBefore, cumulativeAdoptersAfter), x0);
So fsolve() sees a function taking only a single argument (a vector with two elements) and it also returns a vector value.