Solve optimization using fmincon MATLAB when objective function is in constraints - matlab

I want to solve:
I use following MATLAB code, but it does not work.
Can someone please guide me?
function f=objfun
f=-f;
function [c1,c2,c3]=constraint(x)
a1=1.1; a2=1.1; a3=1.1;
c1=f-log(a1)-log(x(1)/(x(1)+1));
c2=f-log(a2)-log(x(2)/(x(2)+1))-log(1-x(1));
c3=f-log(a3)-log(1-x(1))-log(1-x(2));
x0=[0.01;0.01];
[x,fval]=fmincon('objfun',x0,[],[],[],[],[0;0],[1;1],'constraint')

You need to flip the problem around a bit. You are trying to find the point x (which is (l_1,l_2)) that makes the minimum of the 3 LHS functions the largest. So, you can rewrite your problem as, in pseudocode,
maximise, by varying x in [0,1] X [0,1]
min([log(a1)+log(x(1)/(x(1)+1)) ...
log(a2)+log(x(2)/(x(2)+1))+log(1-x(1)) ...
log(a3)+log(1-x(1))+log(1-x(2))])
Since Matlab has fmincon, rewrite this as a minimisation problem,
minimise, by varying x in [0,1] X [0,1]
max(-[log(a1)+log(x(1)/(x(1)+1)) ...
log(a2)+log(x(2)/(x(2)+1))+log(1-x(1)) ...
log(a3)+log(1-x(1))+log(1-x(2))])
So the actual code is
F=#(x) max(-[log(a1)+log(x(1)/(x(1)+1)) ...
log(a2)+log(x(2)/(x(2)+1))+log(1-x(1)) ...
log(a3)+log(1-x(1))+log(1-x(2))])
[L,fval]=fmincon(F,[0.5 0.5])
which returns
L =
0.3383 0.6180
fval =
1.2800

Can also solve this in the convex optimization package CVX with the following MATLAB code:
cvx_begin
variables T(1);
variables x1(1);
variables x2(1);
maximize(T)
subject to:
log(a1) + x1 - log_sum_exp([0, x1]) >= T;
log(a2) + x2 - log_sum_exp([0, x2]) + log(1 - exp(x1)) >= T;
log(a3) + log(1 - exp(x1)) + log(1 - exp(x2)) >= T;
x1 <= 0;
x2 <= 0;
cvx_end
l1 = exp(x1); l2 = exp(x2);
To use CVX, each constraint and the objective function has to be written in a way that is proveably convex using CVX's ruleset. Making the substitution x1 = log(l1) and x2 = log(l2) allows one to do that. Note that: log_sum_exp([0,x1]) = log(exp(0) + exp(x1)) = log(1 + l1)
This also returns the answers: l1 = .3383, l2 = .6180, T = -1.2800

Related

How to use matlab to quickly judge whether a function is convex?

For example, FX = x ^ 2 + sin (x)
Just for curiosity, I don't want to use the CVX toolbox to do this.
You can check this within some interval [a,b] by checking if the second derivative is nonnegative. For this you have to define a vector of x-values, find the numerical second derivative and check whether it is not too negative:
a = 0;
b = 1;
margin = 1e-5;
point_count = 100;
f=#(x) x.^2 + sin(x);
x = linspace(a, b, point_count)
is_convex = all(diff(x, 2) > -margin);
Since this is a numerical test, you need to adjust the parameter to the properties of the function, that is if the function does wild things on a small scale we might not be able to pick it up. E.g. with the parameters above the test will falsely report the function f=#(x)sin(99.5*2*pi*x-3) as convex.
clear
syms x real
syms f(x) d(x) d1(x)
f = x^2 + sin(x)
d = diff(f,x,2)==0
d1 = diff(f,x,2)
expSolution = solve(d, x)
if size(expSolution,1) == 0
if eval(subs(d1,x,0))>0
disp("condition 1- the graph is concave upward");
else
disp("condition 2 - the graph is concave download");
end
else
disp("condition 3 -- not certain")
end

Solving integral for x in MATLAB, where x is bound and part of the integrand

I am trying to solve an equation for x in Matlab, but keep getting the error:
Empty sym: 0-by-1
The equation has an integral, where x is the upper bound and also part of the integrand 1. The code I use is the following:
a = 0.2; b= 10; c = -10; d = 15; mu = 3; sig = 1;
syms x t
eqn = 0 == a + b*normcdf(x,mu,sig)+c*int( normcdf(d + x - t,mu,sig)*normpdf(t,mu,sig),t,0,x);
A = vpasolve(eqn,x)
Any hints on where I am wrong?
I believe that the symbolic toolbox may not be good enough to solve that integral... Maybe some assume or some other trick can do the job, I personally could not find the way.
However, to test if this is solvable, I tried Wolfram Alpha. It gives a result, that you can use.
eq1=a + b*normcdf(x,mu,sig);
resint=c*(t^3*(d - t + x)*erfc((mu - x)/(sqrt(2)*sig)))/(4*sig*exp((-mu + x)^2/(2*sig^2))*sqrt(2*pi));
A=vpasolve(eq1+subs(resint,t,x)-subs(resint,t,0) ==0)
gives 1.285643225712432599485355373093 in my PC.

Using matlab to find a function minimum through secant method

xM(t) = −11.9084 + 57.9117 cos(2πt/87.97), yM(t) = 56.6741 sin(2πt/87.97) and xE(t) = −2.4987 + 149.6041 cos(2πt/365.25), yE(t) = 149.5832 sin(2πt/365.25) represent the positions of Mercury and Earth on an xy-plane, where the sun is at (0,0) and t is the passage of time. I'd like to find the minimum distance between the planets over the next 1000 days by finding the minimum of the function f(t) = ((xE(t) − xM(t))^2 + (yE(t) − yM(t))^2)^(1/2) with a matlab program that implements the secant method.
function [r,N] = SECANT(x0,x1,eps,Nmax,f)
N = 1;
while (N <= Nmax) && (abs(x1-x0) >= eps)
r = x1 - f(x1)*((x1-x0)/(f(x1)-f(x0)));
x0 = x1;
x1 = r;
N = N+1;
end
r
N
The above is what I have for the secant method. I think it should work, but it's possible I made a mistake with it. And this is what I have in matlab to actually solve the problem.
p = #(t) (((-2.4987 + 149.6041*cos(2*pi*t/365.25))-(-11.9084 + 57.9117*cos(2*pi*t/87.97))).^2+((149.5832*sin(2*pi*t/365.25))-(56.6741*sin(2*pi*t/87.97))).^2).^(1/2);
y = SECANT(x0,x1,eps,Nmax,p)
I know that only p is the appropriate thing to pass to the function. I could make up eps (level of precision), and Nmax (maximum number of iterations), but I can't figure out what the parameters x0 and x1 should be.

Solving Set of Second Order ODEs with Matlab ODE45 function

Introduction
NOTE IN CODE AND DISUSSION:
A single d is first derivative A double d is second derivative
I am using Matlab to simulate some dynamic systems through numerically solving the governing LaGrange Equations. Basically a set of Second Order Ordinary Differential Equations. I am using ODE45. I found a great tutorial from Mathworks (link for tutorial below) on how to solve a basic set of second order ordinary differential equations.
https://www.mathworks.com/academia/student_center/tutorials/source/computational-math/solving-ordinary-diff-equations/player.html
Based on the tutorial I simulated the motion for an elastic spring pendulum by obtaining two second order ordinary differential equations (one for angle theta and the other for spring elongation) shown below:
theta double prime equation:
M*thetadd*(L + del)^2 + M*g*sin(theta)*(L + del) + M*deld*thetad*(2*L + 2*del) = 0
del (spring elongation) double prime equation:
K*del + M*deldd - (M*thetad^2*(2*L + 2*del))/2 - M*g*cos(theta) = 0
Both equations above have form ydd = f(x, xd, y, yd)
I solved the set of equations by a common reduction of order method; setting column vector z to [theta, thetad, del, deld] and therefore zd = [thetad, thetadd, deld, deldd]. Next I used two matlab files; a simulation file and a function handle file for ode45. See code below of simulation file and function handle file:
Simulation File
%ElasticPdlmSymMainSim
clc
clear all;
%Define parameters
global M K L g;
M = 1;
K = 25.6;
L = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
theta_0 = 0;
thetad_0 = .5;
del_0 = 1;
deld_0 = 0;
initialValues = [theta_0, thetad_0, del_0, deld_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .01;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#OdeFunHndlSpngPdlmSym, timeSpan, initialValues);
Here is the function handle file:
function dz = OdeFunHndlSpngPdlmSym(~, z)
% Define Global Parameters
global M K L g
% Take output from SymDevFElSpringPdlm.m file for fy1 and fy2 and
% substitute into z2 and z4 respectively
% z1 and z3 are simply z2 and z4
% fy1=thetadd=z(2)= -(M*g*sin(z1)*(L + z3) + M*z2*z4*(2*L + 2*z3))/(M*(L + z3)^2)
% fy2=deldd=z(4)=((M*(2*L + 2*z3)*z2^2)/2 - K*z3 + M*g*cos(z1))/M
% return column vector [thetad; thetadd; deld; deldd]
dz = [z(2);
-(M*g*sin(z(1))*(L + z(3)) + M*z(2)*z(4)*(2*L + 2*z(3)))/(M*(L + z(3))^2);
z(4);
((M*(2*L + 2*z(3))*z(2)^2)/2 - K*z(3) + M*g*cos(z(1)))/M];
Question
However, I am coming across systems of equations where the variables can not be solved for explicitly as is the case with spring pendulum example. For one case I have the following set of ordinary differential equations:
y double prime equation
ydd - .5*L*(xdd*sin(x) + xd^2*cos(x) + (k/m)*y - g = 0
x double prime equation
.33*L^2*xdd - .5*L*ydd*sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
L, g, m, k, and C are given parameters.
Note that x'' term appears in y'' equation and y'' term appears in x'' equation so I am not able to use reduction of order method. Can I use Matlab ODE45 to solve the set of ordinary differential equations in the second example in a manner similar to first example?
Thanks!
This problem can be solved by working out some of the math by hand. The equations are linear in xdd and ydd so it should be straightforward to solve.
ydd - .5*L*(xdd*sin(x) + xd^2*cos(x)) + (k/m)*y - g = 0
.33*L^2*xdd - .5*L*ydd*sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
can be rewritten as
-.5*L*sin(x)*xdd + ydd = -.5*L*xd^2*cos(x) - (k/m)*y + g
.33*L^2*xdd - .5*L*sin(x)*ydd = .33*L^2*C*cos(x) - .5*g*L*sin(x)
which is the form A*x=b.
For more complex systems, you can look into the fsolve function.

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.