I have a function that seems to be working correctly when I give it single inputs to test, but I need it to work on a lot of different variables. Right now at the bottom it's evaluating the function with the initial guess of 25, and the index of 50. In playing around with it, I noticed that the index is actually chanding as fsolve runs, so I figure that I have an incomplete understanding of how fsolve is actually running here, but I can't fix it. My end goal is that I'll be able to cycle the index from 1 to 54 in a for loop, and inside that loop, the initial guess will change based on an algorith I already have running. So pretty much I just need to sort out this function input problem.
Here's my code:
function [objfun] = RK_solver( RK_solver_input )
% Redlich/Kwong EOS
index = RK_solver_input(2)
sigma = 1;
epsilon = 0;
omega = 0.08664;
psi = 0.42748;
beta = omega * RK_solver_input(1) / (Input_Data(2)/1.01325) / Tr(index);
alpha = (Tr(index))^(-1/2);
q = psi*alpha/omega/Tr(index);
A = (sigma + epsilon - 1)*beta - 1;
B = (sigma*epsilon - sigma - epsilon)*(beta^2) + (q - sigma - epsilon)*beta;
C = -(sigma*epsilon*(1+beta) + q)*(beta^2);
Q = ((A^2) - 3*B)/9;
R = (2*(A^3) - 9*A*B + 27*C)/54;
M = R^2 - Q^3;
if M < 0
theta = acos(R/(sqrt(Q*Q*Q)));
Z(1) = -2*(Q^0.5)*(cos(theta/3)) - (A/3);
Z(2) = -2*(Q^0.5)*(cos((theta + 2*pi)/3)) - (A/3);
Z(3) = -2*(Q^0.5)*(cos((theta - 2*pi)/3)) - (A/3);
Z_liquid = min(Z);
Z_vapor = max(Z);
I_liquid = (1/(sigma-epsilon))*log((Z_liquid+sigma*beta)/(Z_liquid+epsilon*beta));
I_vapor = (1/(sigma-epsilon))*log((Z_vapor+sigma*beta)/(Z_vapor+epsilon*beta));
ln_phi_liquid = Z_liquid - 1 - log(Z_liquid - beta) - q*I_liquid;
ln_phi_vapor = Z_vapor - 1 - log(Z_vapor - beta) - q*I_vapor;
objfun = (ln_phi_liquid - ln_phi_vapor);
end
end
RK_solver_guess = [25 50];
Psat_RK_solved = fsolve(#RK_solver, RK_solver_guess)
The issue that you are seeing is because fsolve assumes that it can change any of the parameters specified as the second input to fsolve. In your example you pass the index as part of this initial guess, so fsolve includes the index in the optimization. As a result, fsolve is attempting to modify your real parameter (as you intended) as well as the index in an attempt to minimize the function.
Instead, you will want to specify the index as an input to just the function but not as a parameter for fsolve to use in the minimization.
You can accomplish this by modifying your anonymous function
% Can be whatever you want them to be
guesses = rand(54, 1);
for index = 1:numel(guesses)
solution(index) = fsolve(#(guess)RK_solver(guess, index), guesses(index));
end
If you break down that anonymous function, you'll see that fsolve will supplies the guess variable and then I will add the index variable myself to the function call to RK_solver.
Obviously, you would also need to modify your function definition slightly to handle the parameters and index as two parameters rather than a vector.
function objfun = RK_solver(RK_solver_input, index)
Related
I am trying to use my second order Adams-Bashforth function here:
function [t,x] = Adams(f,t_max,x0,N)
h = t_max/N;
t = linspace(0,t_max,N+1);
x = zeros(2,N+1);
x(:,1) = x0;
x(:,2) = x0 + h.*(f(t(1),x(:,1)));
for i=2:N
x(:,i+1) = x(:,i) + h.*((3/2.*f(t(i),x(:,i))-(1/2).*f(t(i-1),x(:,i-1))));
end
end
In order to solve the Lorenz System Equation. However, whenever I try to call the function, I get an error.
sigma = 10;
beta = 8/3;
rho = 28;
f = #(t,a) [-sigma*a(1) + sigma*a(2); rho*a(1) - a(2) - a(1)*a(3); -beta*a(3) + a(1)*a(2)];
[t,a] = Adams(f,10,[1 1 1],100);
plot3(a(:,1),a(:,2),a(:,3))
Output:
"Unable to perform assignment because
the size of the left side is 2-by-1 and
the size of the right side is 1-by-3.
Error in Project>Adams (line 55)
x(:,1) = x0;"
Is the issue with my function, or with how I am calling my function? Any help would be appreciated.
in line 5 of your Adams function: x(:,1) = x0;
the input x0 is the initial conditions [1 1 1] a row vector of size [3x1], but x is an array of size zeros(2,N+1), or [2x101].
There are several mistakes here, the first you assign a row vector to a colon vector, not only that, but the size of the container in that first column of array x which is [2x1] , that is a different size than the size of x0. that is what the error tells you.
The function is buggy there , and it wont work unless you debug it according to the original intent of that method you are trying to implement.
note that also in the script f=#(t,... is expected to have an input t, but there is not t in the expression [-sigma*a(1) + sigma*a(2); rho*a(1) - a(2) - a(1)*a(3); -beta*a(3) + a(1)*a(2)];
I want to maximize this function using fminbnd in MATLAB.
I am not able to correctly define the function in MATLAB. How can I create a loop for i to define the function accordingly and finally apply fminbnd?. Here's my code (which is actually wrong):
k = 0.1;
L = sum(k - (i/n)) + sum(((i/n) - k)*log(k - (i/n))) + k;
fminbnd(-L, [], []);
Any help will be very appreciated.
There are two things concerning your problem.
First: the thing with the loop
MATLAB is great at vectorizing stuff. The command sum adds-up a vector, so you need to create the vector i = 1:n (from 1 to n... spaced by 1) yourself:
n = 10; % maximum in sum
i = 1:n; % line-space => use MATLAB's vetorization
in = i/n; % put this in a new variable for the sake of conciseness
k = 10; % some random value
L = sum( (k - in) + (in - k).*log(k - in) + k )
the output is:
L =
-17.7921
Second: the thing with optimizing a function
Handing over functions in MATLAB can be done with function handles. Essentially, this is an object pointing to a function. In your case, we in fact need an anonymous function handle:
L = #(k) sum( (k - in) + (in - k).*log(k - in) + k )
The variable in is "frozen". For the anonymous function handle it is as if in was hard coded. The # indicates a function handle and the followed (k) denotes that the variable k should be considered as the first input of this new function (this is why it is an anonymous function handle. The variable k becomes and anonym input).
So you could now call
L(10)
and would obtain
L =
-17.7921
as before.
Now the optimization function can use this (note that you need to include the minus in the function handle, so we just wrap it in a new one:)
fnc = #(k) -L(k)
lb = 1+10-9; % lower bound
ub = 100; % upper bound
[k_opt,fval] = fminbnd(fnc ,lb,ub)
k_opt =
3.2835
fval =
-32.5310
Be aware that your function becomes complex for values k <= 1, which is why I have restricted the minimum bound here to larger values.
I am currently involved in a group project where we have to conduct portfolio selection and optimisation. The paper being referenced is given here: (specifically page 5 and 6, equations 7-10)
http://faculty.london.edu/avmiguel/DeMiguel-Nogales-OR.pdf
We are having trouble creating the optimisation problem using M-Portfolios, given below
min (wrt w,m) (1/T) * sum_(rho)*(w'*r_t - m) (Sorry I couldn't get the formatting to work)
s.t. w'e = 1 (just a condition saying that all weights add to 1)
So far, this is what we have attempted:
function optPortfolio = portfoliofminconM(returns,theta)
% Compute the inputs of the mean-variance model
mu = mean(returns)';
sigma = cov(returns);
% Inputs for the fmincon function
T = 120;
n = length(mu);
w = theta(1:n);
m = theta((n+1):(2*n));
c = 0.01*ones(1,n);
Aeq = ones(1,(2*n));
beq = 1;
lb = zeros(2,n);
ub = ones(2,n);
x0 = ones(n,2) / n; % Start with the equally-weighted portfolio
options = optimset('Algorithm', 'interior-point', ...
'MaxIter', 1E10, 'MaxFunEvals', 1E10);
% Nested function which is used as the objective function
function objValue = objfunction(w,m)
cRp = (w'*(returns - (ones(T,1)*m'))';
objValue = 0;
for i = 1:T
if abs(cRp(i)) <= c;
objValue = objValue + (((cRp(i))^2)/2);
else
objValue = objValue + (c*(abs(cRp(i))-(c/2)));
end
end
The problem starts at our definitions for theta being used as a vector of w and m. We don't know how to use fmincon with 2 variables in the objective function properly. In addition, the value of the objective function is conditional on another value (as shown in the paper) and this needs to be done over a rolling time window of 120 months for a total period of 264 months.(hence the for-loop and if-else)
If any more information is required, I will gladly provide it!
If you can additionally provide an example that deals with a similar problem, can you please link us to it.
Thank you in advance.
The way you minimize a function of two scalars with fmincon is to write your objective function as a function of a single, two-dimensional vector. For example, you would write f(x,y) = x.^2 + 2*x*y + y.^2 as f(x) = x(1)^2 + 2*x(1)*x(2) + x(2)^2.
More generally, you would write a function of two vectors as a function of a single, large vector. In your case, you could rewrite your objfunction or do a quick hack like:
objfunction_for_fmincon = #(x) objfunction(x(1:n), x(n+1:2*n));
I am trying to learn Matlab as someone with an R background. I have the following program written for an iteration that I would like to repeat until the specified condition is met. I believe that I have all of code written for Matlab, except for the command that the iteration should repeat infinitely times until the condition is met (denoted below).
Would someone be able to tell me how to translate this to Matlab syntax? I think that I should be using a while-loop, but I'm not sure since the iterations should continue until a condition is met rather than continuing while some condition is met. Is there an until equivalent? Thank you!
function xn = newton_v2(f,fd,x0,tol)
% newton iteration
xn = x0;
repeat{ %%% 'This is how I would begin the repeat command in R'
% evaluate function and derivative
fxn = feval(f,xn);
fdxn = feval(fd,xn);
% newton iteration step
xnp1 = xn - fxn/fdxn;
if(abs(xnp1 - xn)/abs(xnp1) < tol)
xn<-xnp1
end
% update
xn = xnp1;
} %%% 'This is how I would end the repeat command in R'
end
Also, please let me know if you see anything else wrong in my Matlab code.
I'm not great with R syntax, but you would have two options 1.pass in an array of values to a matlab for loop and iterate through them. Then graph it to find the best solution and try to get more precise from there 2. Set a condition on a while loop. I think you are looking more for a while loop, so you'll put your condition in there. It may be more computationally heavy, but depending on the funct. may be fine.
I do the Newton method with a while loop though the recursive version in the answer by hamaney is interesting. I do this by passing a function handle, initial guess and tolerance to a function.
function x1 = NewtonMethod(f,x,tol)
% dtol is calculated from eps based on the function handle...not shown
xi = f(x); % initial guess
dxi = (f(x+dtol) - f(x-dtol)) / (2 * dtol);
x1 = x - xi / dxi;
while (abs(x1 - x) < tol)
x = x1;
xi = f(x);
dxi = (f(x+dtol) - f(x-dtol)) / (2 * dtol);
x1 = x - xi / dxi;
end
end
There is a problem with this approach. If the initial guess is poorly conditioned or the function unbounded it is possible for this to be an infinite loop. Because of this I include a loop counter and normally break when that counter reaches a maxSteps value.
Adding the inifinite loop protection looks something like this.
xi = f(x); % initial guess
dxi = (f(x+dtol) - f(x-dtol)) / (2 * dtol);
x1 = x - xi / dxi;
loopCounter = 0;
while (abs(x1 - x) < tol)
x = x1;
xi = f(x);
dxi = (f(x+dtol) - f(x-dtol)) / (2 * dtol);
x1 = x - xi / dxi;
loopCounter = loopCounter + 1;
if loopCounter > maxSteps
% include warning message
break
end
end
Do you mean the syntax for the for loop?
If you are trying to create Newton's method, see my own implementation script
y is the function
x0 - first initial value
n - # of xns to approximate
function Xn = newtonsMethod (y,x0,n,startDomain,endDomain)
%the tangent line at any point on the curve
y1 = matlabFunction(diff(sym(y)));
Xn = x0;
x= linspace(startDomain,endDomain,1000);
%recursive call for the newton formula
for i = 1 : n
%find the tangent line
L =#(x)(y1(Xn).*(x-Xn)+y(Xn));
%find the root
Xn = Xn - (y(Xn)./y1(Xn));
end
end
This might be not the best way to do it. but it could help!
I tried to write the 'dumb' version of Euler's method using Matlab but I always came up with nothing. My code was trash :-(
See this pseudocode for this method :
‘set integration range
xi = 0
xf = 0
‘initialize variables
x = xi
y = 1
‘set step size and determine
‘number of calculation steps
dx = 0.5
nc = (xf – xi) / dx
‘ output initial condition
PRINT x, y
‘Loop to implement Euler’s method
‘and display results
DOFOR I = 1, nc
dydx = -(2X**3) + (12X**2) - (20X) + 8.5
y = y + dydx . dx
x = x + dx
PRINT x, y
END DO
I'm pretty sure that this pseudocode is what I need to implement, but I failed to convert it into Matlab code.
Any help please ?
I am not sure where you're failing, it would really help to know how you're failing or what's a complication. Otherwise this just seems like doing your homework.
Here's my attempt at the MATLAB code. (Note: I do not have MATLAB on this computer and have not tested it)
i = 0;
stepsize = .1; % Define as what you want it to be
y = 1; % Initial value condition given
t = 0; % Initial time value
yout = [zeros(1,20)]; % Assuming you want 20 outputs, can change
fvec = [zeros(1,20)];
for i = 1:20 % Time range, can change to correspond to what you want
fvec(i) = 2 - exp(-4*t) - 2*yout(i); % Just loops calculating based on Euler's method
yout(i+1) = yout(i) + stepsize*fvec(i)
t = t+stepsize % Time has passed, increment the time.
end
I'm not entirely sure this code, but it should give you an example of how to go about this. Please comment if something is wrong.