Muller method in Matlab doesn't find complex roots - matlab

My problem is that my Mullers method algorithm in Matlab doesn’t find the complex roots only real. It doesn’t matter which point I choose. My algorithm only finds -1.9713 in range [-2, 0] and 1.4660 in range [1 2] after using the roots function I know that roots are:
roots([2 0.5 -5 2 -3])
ans =
-1.9713
1.4660
0.1276 + 0.7090i
0.1276 - 0.7090i
Here is my code:
function [sol,sol2,i] = Muller2()
min=-2;
max=0;
f=[2 0.5 -5 2 -3]
x=min
for i=1:Inf
%calculating coefficients of the quadratic equation
a=polyval(polyder(polyder(f)), x)/2;
b=polyval(polyder(f), x);
c=polyval(f, x);
%solving delta
d=b^2-4*a*c;
%calculating roots
z1=-2*c/(b+sqrt(d));
z2=-2*c/(b-sqrt(d));
%choosing the closer root
if(abs(polyval(f, z1))<=abs(polyval(f, z2)))
x=x+z1;
else
x=x+z2;
end
sol2(i)=x
if(abs(polyval(f,x))<=20*eps)
break;
end
end
sol=x

I figured it out. In this fragment of code:
%choosing the closer root
if(abs(polyval(f, z1))<=abs(polyval(f, z2)))
x=x+z1;
else
x=x+z2;
end
I changed this:
if(abs(polyval(f, z1))<=abs(polyval(f, z2)))
to this:
if(abs(z1))<=abs(z2))
and the algorithm is now working correctly

Related

How can I get all solutions to this equation in MATLAB?

I would like to solve the following equation: tan(x) = 1/x
What I did:
syms x
eq = tan(x) == 1/x;
sol = solve(eq,x)
But this gives me only one numerical approximation of the solution. After that I read about the following:
[sol, params, conds] = solve(eq, x, 'ReturnConditions', true)
But this tells me that it can't find an explicit solution.
How can I find numerical solutions to this equation within some given range?
I've never liked using solvers "blindly", that is, without some sort of decent initial value selection scheme. In my experience, the values you will find when doing things blindly, will be without context as well. Meaning, you'll often miss solutions, think something is a solution while in reality the solver exploded, etc.
For this particular case, it is important to realize that fzero uses numerical derivatives to find increasingly better approximations. But, derivatives for f(x) = x · tan(x) - 1 get increasingly difficult to accurately compute for increasing x:
As you can see, the larger x becomes, the better f(x) approximates a vertical line; fzero will simply explode! Therefore it is imperative to get an estimate as closely to the solution as possible before even entering fzero.
So, here's a way to get good initial values.
Consider the function
f(x) = x · tan(x) - 1
Knowing that tan(x) has Taylor expansion:
tan(x) ≈ x + (1/3)·x³ + (2/15)·x⁵ + (7/315)·x⁷ + ...
we can use that to approximate the function f(x). Truncating after the second term, we can write:
f(x) ≈ x · (x + (1/3)·x³) - 1
Now, key to realize is that tan(x) repeats with period π. Therefore, it is most useful to consider the family of functions:
fₙ(x) ≈ x · ( (x - n·π) + (1/3)·(x - n·π)³) - 1
Evaluating this for a couple of multiples and collecting terms gives the following generalization:
f₀(x) = x⁴/3 - 0π·x³ + ( 0π² + 1)x² - (0π + (0π³)/3)·x - 1
f₁(x) = x⁴/3 - 1π·x³ + ( 1π² + 1)x² - (1π + (1π³)/3)·x - 1
f₂(x) = x⁴/3 - 2π·x³ + ( 4π² + 1)x² - (2π + (8π³)/3)·x - 1
f₃(x) = x⁴/3 - 3π·x³ + ( 9π² + 1)x² - (3π + (27π³)/3)·x - 1
f₄(x) = x⁴/3 - 4π·x³ + (16π² + 1)x² - (4π + (64π³)/3)·x - 1
⋮
fₙ(x) = x⁴/3 - nπ·x³ + (n²π² + 1)x² - (nπ + (n³π³)/3)·x - 1
Implementing all this in a simple MATLAB test:
% Replace this with the whole number of pi's you want to
% use as offset
n = 5;
% The coefficients of the approximating polynomial for this offset
C = #(npi) [1/3
-npi
npi^2 + 1
-npi - npi^3/3
-1];
% Find the real, positive polynomial roots
R = roots(C(n*pi));
R = R(imag(R)==0);
R = R(R > 0);
% And use these as initial values for fzero()
x_npi = fzero(#(x) x.*tan(x) - 1, R)
In a loop, this can produce the following table:
% Estimate (polynomial) Solution (fzero)
0.889543617524132 0.860333589019380 0·π
3.425836967935954 3.425618459481728 1·π
6.437309348195653 6.437298179171947 2·π
9.529336042900365 9.529334405361963 3·π
12.645287627956868 12.645287223856643
15.771285009691695 15.771284874815882
18.902410011613000 18.902409956860023
22.036496753426441 22.036496727938566 ⋮
25.172446339768143 25.172446326646664
28.309642861751708 28.309642854452012
31.447714641852869 31.447714637546234
34.586424217960058 34.586424215288922 11·π
As you can see, the approximant is basically equal to the solution. Corresponding plot:
To find a numerical solution to a function within some range, you can use fzero like this:
fun = #(x)x*tan(x)-1; % Multiplied by x so fzero has no issue evaluating it at x=0.
range = [0 pi/2];
sol = fzero(fun,range);
The above would return just one solution (0.8603). If you want additional solutions, you will have to call fzero more times. This can be done, for example, in a loop:
fun = #(x)tan(x)-1/x;
RANGE_START = 0;
RANGE_END = 3*pi;
RANGE_STEP = pi/2;
intervals = repelem(RANGE_START:RANGE_STEP:RANGE_END,2);
intervals = reshape(intervals(2:end-1),2,[]).';
sol = NaN(size(intervals,1),1);
for ind1 = 1:numel(sol)
sol(ind1) = fzero(fun, mean(intervals(ind1,:)));
end
sol = sol(~isnan(sol)); % In case you specified more intervals than solutions.
Which gives:
[0.86033358901938;
1.57079632679490; % Wrong
3.42561845948173;
4.71238898038469; % Wrong
6.43729817917195;
7.85398163397449] % Wrong
Note that:
The function is symmetric, and so are its roots. This means you can solve on just the positive interval (for example) and get the negative roots "for free".
Every other entry in sol is wrong because this is where we have asymptotic discontinuities (tan transitions from +Inf to -Inf), which is mistakenly recognized by MATLAB as a solution. So you can just ignore them (i.e. sol = sol(1:2:end);.
Multiply the equation by x and cos(x) to avoid any denominators that can have the value 0,
f(x)=x*sin(x)-cos(x)==0
Consider the normalized function
h(x)=(x*sin(x)-cos(x)) / (abs(x)+1)
For large x this will be increasingly close to sin(x) (or -sin(x) for large negative x). Indeed, plotting this this is already visually true, up to an amplitude factor, for x>pi.
For the first root in [0,pi/2] use the Taylor approximation at x=0 of second degree x^2-(1-0.5x^2)==0 to get x[0]=sqrt(2.0/3) as root approximation, for the higher ones take the sine roots x[n]=n*pi, n=1,2,3,... as initial approximations in the Newton iteration xnext = x - f(x)/f'(x) to get
n initial 1. Newton limit of Newton
0 0.816496580927726 0.863034004302817 0.860333589019380
1 3.141592653589793 3.336084918413964 3.425618459480901
2 6.283185307179586 6.403911810682199 6.437298179171945
3 9.424777960769379 9.512307014150883 9.529334405361963
4 12.566370614359172 12.635021895208379 12.645287223856643
5 15.707963267948966 15.764435036320542 15.771284874815882
6 18.849555921538759 18.897518573777646 18.902409956860023
7 21.991148575128552 22.032830614521892 22.036496727938566
8 25.132741228718345 25.169597069842926 25.172446326646664
9 28.274333882308138 28.307365162331923 28.309642854452012
10 31.415926535897931 31.445852385744583 31.447714637546234
11 34.557519189487721 34.584873343220551 34.586424215288922

Jacobian function returning error "Undefined function 'jacobian' for input arguments of type 'double'"

I'm trying to use a Jacobian to solve an equation using the Newton Raphson method but I keep getting a type 'double' error. Symbolic is installed as well. I am wondering if I am using F correctly here. Do I have to use the Jacobian separately for F(1) and F(2)? Here is the script:
X=[0.75 0.25]; %N-dimensional array, first guess then solution
Y=[0 0];
F(1)=(X(1)^2)+(X(2)^2)-1; %right hand side functions
F(2)=X(1)+X(2)-1; %right hand side functions
MAXIT=10;
ITEST=1;
counter=0;
ABSER=0.00001;
RELER=.1;
DFDX=jacobian(F,X);
[X,ITEST,counter] =NLNR(X,F,MAXIT,counter,ABSER,RELER,ITEST,DFDX);
fprintf('answer for X1 is %d and X2 is %d and ITEST is %d.\n',X(1),X(2),ITEST);
fprintf('number of interations is %d.\n',counter);
and this is the function:
function [X,ITEST,counter] =NLNR(X,F,MAXIT,counter,ABSER,RELER,ITEST)
while ITEST==1 %run loop as long as ITEST is 1
counter=counter+1; %use counter to keep track of iterations
dX=DFDX/(-F);
X=X+dX;
if abs(Y(1)-X(1))<ABSER %check convergence
ITEST=3;
end
if abs((Y(1)-X(1))/X(1))<RELER %check convergence
ITEST=3;
end
if counter>MAXIT %check divergence
ITEST=2;
end
Y(1)=X(1); %set Y to check diff in next loop
Y(2)=X(2);
end
end
It looks like you can easily convert your incorrect use of the symbolic jacobian function to use symbolic math:
X = [0.75 0.25];
x = sym('x',[1 2]);
F = [x(1)^2+x(2)^2-1;
x(1)+x(2)-1];
DFDX = jacobian(F,x)
DFDX_sub = subs(DFDX,x,X)
which returns
DFDX =
[ 2*x1, 2*x2]
[ 1, 1]
DFDX_sub =
[ 3/2, 1/2]
[ 1, 1]
Then you can use double to convert DFDX_sub to a floating point array. Note that the first argument to jacobian can also be a handle to a function that returns a vector (as opposed to a symbolic function or expression):
X = [0.75 0.25];
x = sym('x',[1 2]);
F = #(x)[x(1)^2+x(2)^2-1;
x(1)+x(2)-1];
DFDX = jacobian(F,x)
DFDX_sub = subs(DFDX,x,X)
There is no function called jacobian present in your matlab installation. If you read the documentation you will notice that both functions with that name are part of a toolbox:
http://www.mathworks.com/help/symbolic/jacobian.html
http://www.mathworks.com/help/mbc/mbccommandline/jacobian.html
Probably you don't have these toolboxes installed or licensed.
Best solution for you would probably be to search at matlab file exchange for an implementation which matches your requirements.

How to find Multi variables using GA in matlab?

Here is my model:
Solving this problem, I used GA in matlab
function F = sim_fit(q,k,m)
%retailer
a(1,1)=3;a(2,1)=2;a(3,1)=3;a(1,2)=1;a(2,2)=1.1;a(3,2)=9;
d(1,1)=1850;d(2,1)=2000;d(3,1)=3000;d(1,2)=2100;d(2,2)=1300;d(3,2)=900;
hr(1,1)=2.4;hr(2,1)=1.3;hr(3,1)=38;hr(1,2)=4.5;hr(2,2)=3.6;hr(3,2)=45;
so(1,1)=3.5;so(2,1)=1.5;so(3,1)=2.5;so(1,2)=0.3;so(2,2)=0.6;so(3,2)=6.3;
t(1,1)=1;t(2,1)=1;t(3,1)=3;t(1,2)=1;t(2,2)=1;t(3,2)=3;
E(1,1)=2;E(2,1)=2;E(3,1)=10;E(1,2)=2;E(2,2)=2;E(3,2)=10;
Y(1,1)=3;Y(2,1)=3;Y(3,1)=11;Y(1,2)=3;Y(2,2)=3;Y(3,2)=11;
%vendor
S=100;
hv(1)=3.5;hv(2)=4;
C(1)=10; C(2)=50;
Cv(1)=2.4; Cv(2)=3;
Cf(1)=3; Cf(2)=1.2;
s(1)=0.3; s(2)=0.1;
the(1)=0.01; the(2)=0.03;
dv(1)=sum(d(1,1)+d(1,2));dv(2)=sum(d(2,1)+d(2,2));
Q(1)=sum(q(1,1)+q(1,2));Q(2)=sum(q(2,1)+q(2,2));
P(1)=10000; P(2)=8000;
%function
for j=1:2
for i=1:2
F= S*dv(i)/(Q(i)*m(i,j))+(hv(i)*Q(i)*((m(i)-1)*(1-dv(i)/P(i))+dv(i)/P(i)))/2+...
dv(i)*(m(i)*C(i)+m(i)*Q(i)*Cv(i)+Cf(i))+m(i)*s(i)*dv(i)*Q(i)*the(i)/2+...
a(i,j).*d(i,j)./q(i,j)+(hr(i,j).*((1-k(i,j)).^2).*q(i,j))./2+...
k(i,j).^2.*so(i,j).*q(i,j)./2+(m(i)*t(i,j).*d(i,j))./q(i,j)+(m(i)*E(i,j).*d(i,j))./q(i,j)+...
Y(i,j).*d(i,j);
end
end
end
function [C, ceq] = sim_constraint(q,k,m)
B(:,1)=200;B(:,2)=300;
W(:,1)=100;W(:,2)=100;
b(1)=10; b(2)=14;
w(1)=1; w(2)=1.5;
P(1)=10000; P(2)=8000;
C=[(m(1).*q(1,1).*b(1)+m(2).*q(2,1).*b(2))-B(:,1);
(m(1).*q(1,2).*b(1)+m(2).*q(2,2).*b(2))-B(:,2);
(m(1).*q(1,1).*w(1)+m(2).*q(2,1).*w(2))-W(:,1);
(m(1).*q(1,2).*w(1)+m(2).*q(2,2).*w(2))-W(:,2);
m(1)*Q(1)-P(1);m(2)*Q(2)-P(2)
k(1,1)-1;k(1,2)-1;k(2,1)-1;k(2,2)-1];
ceq=[d(1,1)+d(1,2)-dv(1);(d(2,1)+d(2,2))-dv(2);
(q(1,1)+q(1,2))-Q(1);(q(2,1)+q(2,2))-Q(2)];
end
First, I don't know how to input Xij which is binary variable in sim_fitness function.
Second, in order to solve this problem, I use Optimization Toolbox.
Error message said "need more input variable."
How can I fix it?
This is not an answer to your question. But please, please start using matlab as it was intended:) If it was this cumbersome, then people would not be using it.
The net happiness of the human race will increase if you change your existing code to something like this:
function F = sim_fit(q,k,m)
%retailer
a=[3 2 3; 1 1.1 9].'; %or a=[3 1; 2 1.1; 3 9];
d=[1850 2000 3000; 2100 1300 900].';
hr=[2.4 1.3 38; 4.5 3.6 45].';
so=[3.5 1.5 2.5; 0.3 0.6 6.3].';
t=[1 1 3; 1 1 3].';
E=[2 2 10; 2 2 10].';
Y=[3 3 11; 3 3 11].';
%vendor
S=100;
hv=[3.5 4];
C=[10 50];
Cv=[2.4 3];
Cf=[3 1.2];
s=[0.3 0.1];
the=[0.01 0.03];
dv=sum(d(1:2,:),2).'; %row vector like the earlier ones
Q=sum(q(1:2,:),2).';
P=[10000 8000];
%function
for j=1:2
for i=1:2
F= S*dv(i)/(Q(i)*m(i,j))+(hv(i)*Q(i)*((m(i)-1)*(1-dv(i)/P(i))+dv(i)/P(i)))/2+...
dv(i)*(m(i)*C(i)+m(i)*Q(i)*Cv(i)+Cf(i))+m(i)*s(i)*dv(i)*Q(i)*the(i)/2+...
a(i,j).*d(i,j)./q(i,j)+(hr(i,j).*((1-k(i,j)).^2).*q(i,j))./2+...
k(i,j).^2.*so(i,j).*q(i,j)./2+(m(i)*t(i,j).*d(i,j))./q(i,j)+(m(i)*E(i,j).*d(i,j))./q(i,j)+...
Y(i,j).*d(i,j);
end
end
end
function [C, ceq] = sim_constraint(q,k,m)
B=[200 300];
W=[100 100];
b=[10 14];
w=[1 1.5];
P=[10000 8000];
mtmp=reshape(m(1:2),1,[]); %since I don't know its size, be on the safe side
qtmp=q(1:2,1:2); %same thing here
%WHAT IS Q?
%WHAT IS d?
%WHAT IS dv?
C=[((mtmp.*b)*qtmp - B).';
((mtmp.*w)*qtmp - W).';
(mtmp.*Q-P).'; %assuming Q is of size [1, 2]
reshape(k(1:2,1:2).',4,1)-1];
ceq=[sum(d(1:2,1:2),2)-dv.';
sum(q(1:2,1:2),2)-Q.']; %assuming Q is of size [1, 2]
end
Sorry, I didn't have it in me to decrypt your expression for F. I strongly suggest getting familiar with the basic array syntax of matlab, and checking for yourself whether I made any mistakes during the conversion of your code. If you learn how to work with matrices and vectors, expressions like what you have for F can be radically simplified.
Also, the definition of the variables Q, d and dv seem to be missing from your second function. Those aren't globals, are they?

Systems of Differential Equations with initial-value problems

I have a problem with some differential equations of first-order. I'm trying to solve them with ode23 and ode23s. The differential equations are:
y’ – z – u = 0
z’ – u – y = 0
u’ – y – z = 0
with the initial values: y(0) = –1, z(0) = 1, u(0) = 0.
I also want to compare it with the ANALYTICAL solution:
y = – exp(x)
z = exp(x)
u = 0
I want to do it this way because I need to do the comparison in order to choose the better solver: ode23 or ode23s, whichever one is closer to the analytical solution.
My code is:
%y'=z+u
%z'=u+y
%u'=y+z
%y(0)=-1,z(0)=1, u(0)=0 inital values
%y=y(0) z=y(1) u=y(2)
function dy = part1(t,k)
y=k(1);
z=k(2);
u=k(3);
dy=[z+u;u+y;y+z];
and:
%comparıson of numerıcal and analytıcal equatıons
%Fırst comparıson functıon
[t1,y1]=ode23('part1',[0 16],[0 1 -1]);
%Second comparıson functıon
[t2,y2]=ode23s('part1',[0 16],[0 1 -1]);
%ya,za,ua are analytıcal equtıons
ya =(-exp(t1));
za=exp(t1);
ua=0;
%ı have to plot ya,ua and za depends on ode23 and ode23s
%then ı wıll decıde the best solutıon depends on my shape
%either ode23 or ode23s ıs the best?
plot(t1,ya,t1,za,t1,ua);title('ya,za,ua')
figure
plot(t1,y1(:,1),t1,y1(:,2),t1,y1(:,3));title('ode23')
figure
plot(t2,y2(:,1),t2,y2(:,2),t2,y2(:,3));title('ode23s')
But it doesn't work. Could someone help me?

Developing a Secant Method Program for root finding

So I have been trying to develop a secant method program that can be used for finding the root of
f(x) = tanh(x) - (x / 3)
However the answer output is nowhere close. Every solution I have found seems a more complex way to solve it.
x = 2;
prevx = x;
for i = 1:20
x = x - (tanh(x)-(x/3))*((x-(prevx))/((tanh(x)-(x/3))-(tanh(prevx))-((prevx/3))));
prevx = prevx + x;
x
end
The answer should be 2.987. I am getting a negative number though for some reason.
You suppose to add up terms so replace minus in this line:
x = x - (tanh(x)-(x/3))*((x-(prevx))/((tanh(x)-(x/3))-(tanh(prevx))-((prevx/3))));
To a plus:
x = x + (tanh(x)-(x/3))*((x-(prevx))/((tanh(x)-(x/3))-(tanh(prevx))-((prevx/3))));
To get a desired result of 2.987 for x. Also remove x before the end of the loop.
Here is an alternative way to do it (#madbitloman is right on spot as for the error in your code).
The secant method can be illustrated as follows (from Wikipedia):
Now if we translate this into MATLAB code, that would look like this:
x(k) = x(k-1) - (f(x(k-1)))*((x(k-1) - x(k-2))/(f(x(k-1)) - f(x(k-2))));
What is left to be done is provide the algorithm with 2 initial estimates and some tolerance value to tell it when to stop searching for a root, i.e. when 2 consecutive entries in x are very close to each other.
Let's choose 2 and 4. The closer the estimates to the real root, the faster the convergence.
To avoid using tanh(x)-(x/3) inside the for loop, which could get messy, let's define an anonymous function that takes x as an argument:
f = #(x) tanh(x)-(x/3);
So that would be the f in the line of code above.
Therefore, the whole code would look like the following, with a tolerance of say 0.001:
clear
clc
%// Initial values and tolerance
x(1) = 2;
x(2) = 4;
f = #(x) tanh(x)-(x/3);
tolerance = 0.001;
%// Let's try from 3 to 15.
for k=3:15
x(k) = x(k-1) - (f(x(k-1)))*((x(k-1) - x(k-2))/(f(x(k-1)) - f(x(k-2))));
if abs(x(k)-x(k-1)) < tolerance
break
end
end
After running the code, x looks like this:
x =
2.0000 4.0000 2.9420 2.9839 2.9847
so it took 5 iterations to reach the desired tolerance. Note that due to floating arithmetic you might want to use a smaller tolerance because Matlab stores numbers with much more digits than 4.
Finally you can get the negative root as well using appropriate initial estimates like -2 and -4:
x =
-2.0000 -4.0000 -2.9420 -2.9839 -2.9847
Hope that helps somehow!