Solving a piecewise function for a given intercept in Matlab - matlab

I'm trying to solve a piecewise function, but I am getting an error. The following is the code.
script:
syms x
y_intercept = 2;
answerr = solve(pw_f(x) == y_intercept, x);
piecewise function (in a separate file within the same folder):
function y = pw_f(x)
if x < 0
y = x;
elseif (x >=0) && (x <= 20)
y = 2*x;
elseif x > 20
y = 4*x - 40;
else
end
end
The error I'm getting after running the script is:
Conversion to logical from sym is not possible.
Error in pw_f (line 3)
if x < 0
Error in solve_test
answerr = fsolve(pw_f(x) == y_intercept, x);
I know that the error is because Matlab can't perform the comparison x < 0 because x is a symbolic variable, so it does not know what x is yet. I also tried using fsolve, and vpasolve but I'm still getting the same error. Do you know how to solve this in Matlab or get around this error?
Of course, this is an easy problem that I can do in my head (x = 1 is the solution) so Matlab should be able to do this!! However, I want to make this generic for any y-intercept (maybe some random number that is not such a nice whole number) that I choose. PLEASE HELP!!!! Thanks :)
FYI, I am using Matlab R2013a.

In file called pw_f.m
function y = pw_f(x)
if x < 0
y = x;
elseif (x >=0) && (x <= 20)
y = 2*x;
elseif x > 20
y = 4*x - 40;
else
end
end
In command window
>> y_intercept = 2; % set object value
>> x0 = 0; % initial guess
>> answerr = fzero(#(x)pw_f(x) - y_intercept, x0) % solve
answerr =
1
>> pw_f(answerr) % test solution
ans =
2

Related

Fixed point iterative method error MATLAB

I am trying to use the fixed point iteration method with initial approximation x(1)=0 to obtain an approximation to the root of the equation f(x)=3x+sin(x)e^x=0.
The stopping criterion is
|x(k+1)-x(k)|<0.0001
x(1) = 0;
n = 100;
for k = 1:n
f(k) = 3*x(k) +sin(x(k))-exp(x(k));
if (abs(f(k))<0.0001)
break;
end
syms x
diff(f(k));
x(k+1) = x(1)- (f(k))/(diff(f(k)));
end
[x' f']
This is the error I am getting: Error using / Matrix dimensions must
agree. Error in prac2Q2 (line 15)
x(k+1) = x(1)- (f(k))/(diff(f(k)));
I would suggest to calculate the derivative by hand and use that term as denominator or to save the derivative in another variable and use this as the denominator.
Derivative as Variable
f(k) = ...;
df(k) = diff(f(k));
x(k+1) = x(k) - f(k) / df(k);
PS: I cannot test this, because I do not have access to the Symbolic Toolbox right now.
If you're looking for the root of 3*x +sin(x)-exp(x) you want to resolve this equation:
3*x + sin(x) - exp(x) = 0
The easiest way will be to isolate x in one side of the equation:
x = (exp(x) - sin(x))/3 % now iterate until x = (exp(x) - sin(x))/3
Now I would recommand to use an easier fixed point method: x(k+1) = (x(k)+f(x(k)))/2
x = 1 % x0
while 1
y = (exp(x)-sin(x))/3; % we are looking for the root not for a fixed point !!! y = f(x)
x = (x+y)/2 % after a few iterations x == y, so x = (x+y)/2 or x = 2x/2
if abs(x-y) < 1e-10
break
end
end
And you obtain the correct result:
x = 0.36042
No need of symbolic math.

Sort an array of points to generate an envelope in MATLAB

I have the next vectors:
A = [0;100;100;2100;100;2000;2100;2100;0;100;2000;2100;0];
B = [0;0;1450;1450;1550;1550;1550;1550;2500;2500;3000;3000;0]
If we plot A and B, we'll obtain the following graphic:
Then, I wonder how to short the points in order to have the next plot:
As you can see, there're some conditions like: all of them form right angles; there's no intersection between lines.
Thanks in advance for any reply!
This can be solved in the traditional recursive 'maze' solution of 'crawling on walls':
%%% In file solveMaze.m
function Out = solveMaze (Pts,Accum)
if isempty (Pts); Out = Accum; return; end % base case
x = Accum(1, end); y = Accum(2, end); % current point under consideration
X = Pts(1,:); Y = Pts(2,:); % remaining points to choose from
% Solve 'maze' by wall-crawling (priority: right, up, left, down)
if find (X > x & Y == y); Ind = find (X > x & Y == y); Ind = Ind(1);
elseif find (X == x & Y > y ); Ind = find (X == x & Y > y ); Ind = Ind(1);
elseif find (X < x & Y == y); Ind = find (X < x & Y == y); Ind = Ind(1);
elseif find (X == x & Y < y ); Ind = find (X == x & Y < y ); Ind = Ind(1);
else error('Incompatible maze');
end
Accum(:,end+1) = Pts(:,Ind); % Add successor to accumulator
Pts(:,Ind) = []; % ... and remove from Pts
Out = solveMaze (Pts, Accum);
end
Call as follows, given A and B as above;
Pts = [A.'; B.']; Pts = unique (Pts.', 'rows').'; % remove duplicates
Out = solveMaze (Pts, Pts(:,1)); % first point as starting point
plot(Out(1,:), Out(2,:),'-o'); % gives expected plot
If all intersections must be at 90 degree angles, we can form a graph of possible connections.
# in pseudo-code, my matlab is very rusty
points = zip(A, B)
graph = zeros(points.length, points.length) # Generate an adjacency matrix
for i in [0, points.length):
for j in [i + 1, points.length):
if points[i].x == points[j].x or points[i].y == points[j].y:
graph[i][j] = graph[j][i] = 1
else
graph[i][j] = graph[j][i] = 0
Note: it may be important/ improve performance to disconnect colinear points.
After this, the solution is reduced to finding a Hamiltonian Cycle. Unfortunately this is an NP-hard problem, but fortunately, a MATLAB solution already exists: https://www.mathworks.com/matlabcentral/fileexchange/51610-hamiltonian-graph--source--destination- (although I haven't tested it).

How to use integration limits correctly (Matlab)

I've made a script that calculates a given integral with the limits:
0 <= x <= 2 and 0 <= y <= 1
But now I want to change the limits to:
0 <= x <= 2 and 0 <= y <= sin((pi*x)/2)
Function:
function f = inte(x,y)
dz = 10;
f = exp(-dz*((x-1.25).^2+y.^2)).*cos(y.*(x-1.25));
end
This is my script for the earlier limits:
L = 100; M = L/2;
hx = (2)/L; hy = (1)/M;
x=[0:L]*hx;
y=[0:M]*hy;
Fx=[];
for i = 1:L+1
Fy=[];
for j = 1:M+1
f = inte(x(i),y(j));
Fy = [Fy f];
end
ycor = hy*(sum(Fy) - Fy(1)/2 - Fy(end)/2);
Fx = [Fx ycor];
end
ans = hx*(sum(Fx) - Fx(1)/2 - Fx(end)/2);
disp (ans)
I can't seem to get the right answer when I try to change the code. The correct answer should be 0.1560949...
L is amount of steps in x direction, M in y direction. hx and hy are step lengths.
This is really bugging me. And no I can only use the commands integral2 or traps as reference.
Thanks in advance!
In your present code, the lines
hy = (1)/M;
y=[0:M]*hy;
refer to the y-variable. When the limits for y depend on x, these lines cannot stay outside of the loop over x: they should be moved in and use the value x(i). Like this:
for i = 1:L+1 % as in your code
hy = (sin(pi*x(i)/2))/M;
y = [0:M]*hy;
Fy=[]; % this and the rest as in your code
I get output 0.1561, as you wanted.

Newton's method roots on Matlab

I am not so much experiences with Matlab. I just need it for the sake of solving some lengthy non-linear equations. Instead of using fzero, I wanna use Newton-Raphson's to solve the equation.
newton.m file contains the following code.
function [ x, ex ] = newton( f, df, x0, tol, nmax )
if nargin == 3
tol = 1e-4;
nmax = 1e1;
elseif nargin == 4
nmax = 1e1;
elseif nargin ~= 5
error('newton: invalid input parameters');
end
x(1) = x0 - (f(x0)/df(x0));
ex(1) = abs(x(1)-x0);
k = 2;
while (ex(k-1) >= tol) && (k <= nmax)
x(k) = x(k-1) - (f(x(k-1))/df(x(k-1)));
ex(k) = abs(x(k)-x(k-1));
k = k+1;
end
end
And in the main file, I have called this function as follows:
ext_H = newton( exp(x) + x^3, diff(exp(x) + x^3), 9, 0.5*10^-5, 10);
When I run this function, it gives me the following error.
Error using sym/subsref (line 9)
Error using maplemex
Error, (in MTM:-subsref) Array index out of range
Error in newton (line 37)
x(1) = x0 - (f(x0)/df(x0));
Error in main (line 104)
ext_H = newton( exp(x) + x^3, diff(exp(x) + x^3), 9, 0.5*10^-5, 10);
Could anyone please help me to get through this?
You can probably use Matlab's fsolve (http://uk.mathworks.com/help/optim/ug/fsolve.html) with a couple of options
x0 = 9;
options = optimoptions('fsolve','Algorithm','levenberg-marquardt','TolFun',5*10^-6,'MaxIter',100);
x = fsolve(#(x)(exp(x) + x^3), x0,options);
or just fzero (http://uk.mathworks.com/help/optim/ug/fzero.html) which implements BD algorithm
x = fzero(#(x)(exp(x) + x^3), x0);

MATLAB: Conversion to logical from sym is not possible

I'm having a problem with a user defined function I am constructing here. What I'm trying to do is to substitute a value into a symbolic function and then use that numerical answer for various purposes. Specifically here:
x = xo;
subst = subs(f,x);
while((n>i) && (subst > eps))
Running my program, I get the following error:
>> sym_newtonRaphson(f,fdiff,1,1e-8,10)
Conversion to logical from sym is not possible.
Error in sym_newtonRaphson (line 8)
I've tried using double(subs(f,x)) to no avail. I seem to be getting a totally different error relating to MuPAD (DOUBLE cannot convert the input expression into a double array.)
The following is the whole program:
function [output] = sym_newtonRaphson(f,fdiff,xo,eps,n)
i = 0;
%initial iteration
x = xo;
subst = subs(f,x);
while((n>i) && (subst > eps))
x = x - (subs(f,x))/fdiff;
i = i+1;
subst = subs(f,x);
%fprintf('%f\t%f\t%f\t%f\t%f\t%f',i,alpha,f(
end
output = x;
end
I'd appreciate some pointers as to what I'm doing wrong; all the best.
What you're trying to do with the while expression is equivalent to logical(f), where f is a symbolic function (rather than a symbolic value). logical(sym('exp(1)') > 0) is fine, but logical(sym('exp(f)') > 0) is generally not going to be (see assume). Matlab has no way of casting a symbolic variable to a logical (true and false) one. It tries to do this because the short circuit AND operator, &&, isn't supported for symbolic variables. For example
a = 1.5;
syms x;
% All of these will not generate errors
y1 = x > 1;
y2 = x > 1 & x < 2;
y3 = x > 1 & x < 2;
y4 = x > 1 & a < 2;
y5 = x > 1 & a > 2;
% These will result in errors
y2 = x > 1 && x < 2;
y3 = x > 1 && x < 2;
y4 = x > 1 && a < 2;
y5 = x > 1 && a > 2;
You should print out subst and make sure that it is a symbolic value or a function that does not include any variables (if argnames(subst) returns an empty symbolic matrix then you should be okay). The fact that you get the second error when you call double seems to imply that subst is actually an expression that still includes unknown variables. If this is the case, then you'll either need to substitute in other variables or use assumptions (see here) in order to do logical comparisons as you're doing.