How to call automatically symbolic variables in a loop in Matlab - matlab

Is there anyway to use a loop index to call symbolic variables in Matlab? For example, consider the following code whose goal is to store the symbolic expression "x1+x2+x3" in "y".
syms x1 x2 x3
y = 0;
for i = 1:3
y = y + xi;
end
The code does not work because on each iteration Matlab reads "y = y + xi" and returns the error "xi is undefined", instead of reading "y = y + x1", "y = y + x2" and "y = y + x3", is there anyway around this?
Thanks.

I'd suggest this, provided that you can create your numbered symbolic variable slightly differently:
x = sym('x',[1 3]); % or: syms x1 x2 x3; x = [x1 x2 x3];
y = x(1);
for i = 2:numel(x)
y = y+x(i);
end
Of course in this simple example, the entire for loop and everything else can be replaced with:
y = sum(sym('x',[1 3]));
See the documentation on sym for more details.
EDIT: Note that, as #pm89 points out, by allocating the 1-by-3 symbolic vector x, you of course won't have direct access to the symbolic variables x1,x2, and x3 in your workspace, but will have to index them as shown. This is similar to working with arrays or cells and has many of the same benefits as my second vectorized example illustrates.

If your Matlab does not support the matrix declaration of symbolics directly (as sym('x',[3 1])) you can write your own function for that:
function out = Matrix_Sym(name, size) %#ok<STOUT>
rows = size(1);
cols = size(2);
S = '';
for k1 = 1:rows
for k2 = 1:cols
if rows == 1
S = [S name int2str(k2) ' '];
elseif cols == 1
S = [S name int2str(k1) ' '];
else
S = [S name int2str(k1) int2str(k2) ' '];
end
end
end
eval(['syms ' S]);
eval (['out = reshape([' S '], [rows, cols]);']);
Then you could get the same result with:
x = Matrix_Sym('x', [3 1])
...

Related

Taylor Series of ln(x) in Matlab

I am trying to compute the taylor series of ln(x) for any value of x.
What I have so far is:
clear
clc
n = input('Enter number of iiterations (n): ' );
x = input('enter value of x (x): ');
y = zeros(1,n);
for i = 0:n
y(i+1)=sum + (-1)^(n+1)*(x-1)^n/n;
end
But this code seems to be broken and I can't figure out why. Any suggestions on how to improve?
This is a one liner in addition to the for-loop answer provided by #farbiondriven
For 0<x<1 :
sumLn = #(x, n)(sum(((-1).^(0:n-1)).*((x-1).^(1:n))./(1:n)));
sumLn(0.5,10)
ans =
-0.6931
>> log(0.5)
ans =
-0.6931
For x>0.5 :
sumLn = #(x, n)(sum( ((x-1)/x).^(1:n) ./ (1:n) ));
sumLn(2,10)
ans =
0.6931
log(2) =
0.6931
Note: The variable x in this formula is bounded as mentioned in this link.
Try this:
clear
clc
n = input('Enter number of iterations (n): ' );
x = input('enter value of x with abs value < 1 (x): ');
y = zeros(1,n+1);
y(1)=0;
for i = 1:n
y(i+1)= y(i) + ((-1)^(i+1)*(x-1)^i/i);
end
txt = sprintf('The output is: %f', y(n+1))
I suggest using built-in function and hopefully there is one. taylor(f,var) approximates f with the Taylor series expansion of f up to the fifth order at the point var = 0.
Specify Expansion Point :
Find the Taylor series expansions at x = 1 for these functions. The default expansion point is 0. To specify a different expansion point, use 'ExpansionPoint':
syms x
taylor(log(x), x, 'ExpansionPoint', 1)
ans =
x - (x - 1)^2/2 + (x - 1)^3/3 - (x - 1)^4/4 + (x - 1)^5/5 - 1
Specify Truncation Order :
The default truncation order is 6.
syms x
f = log(x);
t6 = taylor(f, x);
Use 'Order' to control the truncation order. For example, approximate the same expression up to the orders 8.
syms x
taylor(log(x), x, 'ExpansionPoint', 1, 'Order', 8);

Attempting Tridiagonal Gauss-Jordan Elimination Matlab

As you probably guessed from the title, I'm attempting to do tridiagonal GaussJordan elimination. I'm trying to do it without the default solver. My answers aren't coming out correct and I need some assistance as to where the error is in my code.
I'm getting different values for A/b and x, using the code I have.
n = 4;
#Range for diagonals
ranged = [15 20];
rangesd = [1 5];
#Vectors for tridiagonal matrix
supd = randi(rangesd,[1,n-1]);
d = randi(ranged,[1,n]);
subd = randi(rangesd,[1,n-1]);
#Creates system Ax+b
A = diag(supd,1) + diag(d,0) + diag(subd,-1)
b = randi(10,[1,n])
#Uses default solver
y = A/b
function x = naive_gauss(A,b);
#Forward elimination
for k=1:n-1
for i=k+1:n
xmult = A(i,k)/A(k,k);
for j=k+1:n
A(i,j) = A(i,j)-xmult*A(k,j);
end
b(i) = b(i)-xmult*b(k);
end
end
#Backwards elimination
x(n) = b(n)/A(n,n);
for i=n-1:-1:1
sum = b(i);
for j=i+1:n
sum = sum-A(i,j)*x(j);
end
x(i) = sum/A(i,i)
end
end
x
Your algorithm is correct. The value of y that you compare against is wrong.
you have y=A/b, but the correct syntax to get the solution of the system should be y=A\b.

Trying to solve Simultaneous equations in matlab, cannot work out how to format the functions

I was given a piece of Matlab code by a lecturer recently for a way to solve simultaneous equations using the Newton-Raphson method with a jacobian matrix (I've also left in his comments). However, although he's provided me with the basic code I cannot seem to get it working no matter how hard I try. I've spent many hours trying to introduce the 'func' function but to no avail, frequently getting the message that there aren't enough inputs. Any help would be greatly appreciated, especially with how to write the 'func' function.
function root = newtonRaphson2(func,x,tol)
% Newton-Raphson method of finding a root of simultaneous
% equations fi(x1,x2,...,xn) = 0, i = 1,2,...,n.
% USAGE: root = newtonRaphson2(func,x,tol)
% INPUT:
% func = handle of function that returns[f1,f2,...,fn].
% x = starting solution vector [x1,x2,...,xn].
% tol = error tolerance (default is 1.0e4*eps).
% OUTPUT:
% root = solution vector.
if size(x,1) == 1; x = x'; end % x must be column vector
for i = 1:30
[jac,f0] = jacobian(func,x);
if sqrt(dot(f0,f0)/length(x)) < tol
root = x; return
end
dx = jac\(-f0);
x = x + dx;
if sqrt(dot(dx,dx)/length(x)) < tol
root = x; return
end
end
error('Too many iterations')
function [jac,f0] = jacobian(func,x)
% Returns the Jacobian matrix and f(x).
h = 1.0e-4;
n = length(x);
jac = zeros(n);
f0 = feval(func,x);
for i =1:n
temp = x(i);
x(i) = temp + h;
f1 = feval(func,x);
x(i) = temp;
jac(:,i) = (f1 - f0)/h;
end
The simultaneous equations to be solved are:
sin(x)+y^2+ln(z)-7=0
3x+2^y-z^3+1=0
x+y+Z-=0
with the starting point (1,1,1).
However, these are arbitrary and can be replaced with anything, I mainly just need to know the general format.
Many thanks, I know this may be a very simple task but I've only recently started teaching myself Matlab.
You need to create a new file called myfunc.m (or whatever name you like) which takes a single input parameter - a column vector x - and returns a single output vector - a column vector y such that y = f(x).
For example,
function y = myfunc(x)
y = zeros(3, 1);
y(1) = sin(x(1)) + x(2)^2 + log(x(3)) - 7;
y(2) = 3*x(1) + 2^x(2) - x(3)^3 + 1;
y(3) = x(1) + x(2) + x(3);
end
You can then refer to this function as #myfunc as in
>> newtonRaphson2(#myfunc, [1;1;1], 1e-6);
The reason for the special notation is that Matlab allows you to call a function with no parameters by omitting the parens () that follow it. So for example, Matlab interprets myfunc as you calling the function with no arguments (so it tries to replace it with its result) whereas #myfunc refers to the function itself, rather than its result.
Alternatively you can write a function directly using the # notation, as in
>> newtonRaphson2(#(x) exp(x) - 3*x, 2, 1e-2)
ans =
1.5315
>> newtonRaphson2(#(x) exp(x) - 3*x, 1, 1e-2)
ans =
0.6190
which are the two roots of the equation exp(x) - 3 * x = 0.
Edit - as an aside, your professor has terrible coding style (if the code in your question is a direct copy-paste of what he gave you, and you haven't mangled it along the way). It would be better to write the code like this, with indentation making it clear what the structure of the code is.
function root = newtonRaphson2(func, x, tol)
% Newton-Raphson method of finding a root of simultaneous
% equations fi(x1,x2,...,xn) = 0, i = 1,2,...,n.
%
% USAGE: root = newtonRaphson2(func,x,tol)
%
% INPUT:
% func = handle of function that returns[f1,f2,...,fn].
% x = starting solution vector [x1,x2,...,xn].
% tol = error tolerance (default is 1.0e4*eps).
%
% OUTPUT:
% root = solution vector.
if size(x, 1) == 1; % x must be column vector
x = x';
end
for i = 1:30
[jac, f0] = jacobian(func, x);
if sqrt(dot(f0, f0) / length(x)) < tol
root = x; return
end
dx = jac \ (-f0);
x = x + dx;
if sqrt(dot(dx, dx) / length(x)) < tol
root = x; return
end
end
error('Too many iterations')
end
function [jac, f0] = jacobian(func,x)
% Returns the Jacobian matrix and f(x).
h = 1.0e-4;
n = length(x);
jac = zeros(n);
f0 = feval(func,x);
for i = 1:n
temp = x(i);
x(i) = temp + h;
f1 = feval(func,x);
x(i) = temp;
jac(:,i) = (f1 - f0)/h;
end
end

How to create symbolic matrix dynamically in MATLAB?

I need to create a symbolic matrix in MATLAB. It can be done statically as
syms a11 a12 a21 a22;
A = [a11 a12; a21 a22];
or using compact syntax as
A = sym('A%d', [2 2]);
However i don't see how any of these syntax's should allow dynamic initialization. I would like to initialize each matrix element individually using two loops. One shot at a possible syntax (it's NOT valid MATLAB syntax) could be
syms a x1;
P = sym(zeros(n,n));
for l = 1:n
for m = 1:n
kl = l; km = m;
P(l,m)(x1) = a*sin(kl*x1)*sin(km*x1);
end
end
where I used the (invalid) syntax P(l,m)(x1) to specify that each element in P is a function of x1. Hence P(2) would be an (n,n) matrix with elements P(l,m) = a*sin(kl*2)*sin(km*2). I know it's possible to construct the P by building the matrix string (A=[...]) on run time and evaluating using eval. Something like
syms a x1;
command = [];
for i = 1:n
for j = 1:n
kl = i; km = j;
command = [command ' + a*sin(' num2str(kl) '*x1)*sin(' num2str(km) '*x1)'];
if(j < n) command = [command ',']; end
end
if(i < n) command = [command ';']; end
end
eval(['P(x1) = [' command '];'])
However, using eval is bad practice, so I see this solution only as a last resort. Is there any correct way to achieve my goal?
NB: I have written the elements P(l,m) = a*sin(kl*x1)*sin(km*x1) to simplify the code. The actual expression is P(l,m) = sin(kl*x1)*sin(km*x1)*epsilon + kl*km*cos(kl*x1)*cos(km*x1).*b + km*cos(km*x1)*sin(kl*x1)-kl*cos(kl*x1)*sin(km*x1)/(kl^2-km^2).
If you're just trying to avoid the for loops, you can use meshgrid, which hides them from you:
syms a x1
n = 3;
x = meshgrid(1:n)*x1; % multiplying by the symbolic x1 makes x symbolic
P = a*sin(x).*sin(x.');
which returns
P =
[ a*sin(x1)^2, a*sin(2*x1)*sin(x1), a*sin(3*x1)*sin(x1)]
[ a*sin(2*x1)*sin(x1), a*sin(2*x1)^2, a*sin(2*x1)*sin(3*x1)]
[ a*sin(3*x1)*sin(x1), a*sin(2*x1)*sin(3*x1), a*sin(3*x1)^2]

variable in solving the equation

I want to solve equations in matlab, eg.
100+a/2=173*cos(b)
sqrt(3)*a/2=173*sin(b)
and the code would be:
[a,b]=solve('100+a/2=173*cos(b)','sqrt(3)*a/2=173*sin(b)','a','b')
However, if I want to take 100 as a variable, like
for k=1:100
[a,b]=solve('k+a/2=173*cos(b)','sqrt(3)*a/2=173*sin(b)','a','b')
end
There would be an error, how to make it?
degree=140/1000000;
p=42164000;
a=6378136.5;
b=6356751.8;
x_1=0;
y_1=p;
z_1=0;
for i=451:550
for j=451:550
alpha=(1145-i)*degree;
beta=(1145-j)*degree;
x_2=p/cos(alpha)*tan(beta);
y_2=0;
z_2=p*tan(alpha);
syms x y z x_1 x_2 y_1 y_2 z_1 z_2 a b
eq = [(x-x_1)*(y2-y_1)-(x_2-x_1)*(y-y_1),(x-x_1)*(z_2-z_1)-(x_2-x_1)*(z-z_1), b^2*(x^2+y^2)+a^2*(y^2)-a^2*b^2 ];
sol = solve(eq(1),x,eq(2),y, eq(3),z);
sol.x
sol.y
sol.z
end
end
I got the expression value, how do I get the numeric value of x,y,z?
[['x(1)=';'x(2)='],num2str(double(sol.x))]
not work ,shows
??? Error using ==> mupadmex
Error in MuPAD command: DOUBLE cannot convert the input expression into a double array.
If the input expression contains a symbolic variable, use the VPA function instead.
Error in ==> sym.sym>sym.double at 927
Xstr = mupadmex('mllib::double', S.s, 0);
Error in ==> f2 at 38
[['x(1)=';'x(2)='],num2str(double(sol.x))]
If you have access to the Symbolic Toolkit then you do the following:
syms a b k
eq = [k+a/2-173*cos(b), sqrt(3)*a/2-173*sin(b)];
sol = solve(eq(1),a,eq(2),b);
sol.a = simplify(sol.a);
sol.b = simplify(sol.b);
% There are two solutions for 'a' and 'b'
% check residuals for example k=20
subs(subs(eq,{a,b},{sol.a(1),sol.b(1)}),k,20)
% ans = 0.2e-13
subs(subs(eq,{a,b},{sol.a(2),sol.b(2)}),k,20)
% ans = 0.2e-13
Edit 1
Based on new code by OP the matlab script to solve this is:
clear all
clc
syms alpha beta
degree=140/1000000;
p=42164000;
a=6378136.5;
b=6356751.8;
x_1=0;
y_1=p;
z_1=0;
x_2 = p/cos(alpha)*tan(beta);
y_2 = 0;
z_2 = p*tan(alpha);
syms x y z
eq = [(x-x_1)*(y_2-y_1)-(x_2-x_1)*(y-y_1);...
(x-x_1)*(z_2-z_1)-(x_2-x_1)*(z-z_1); ...
b^2*(x^2+y^2)+a^2*(y^2)-a^2*b^2 ];
sol = solve(eq(1),x,eq(2),y,eq(3),z);
sol.x = simplify(sol.x);
sol.y = simplify(sol.y);
sol.z = simplify(sol.z);
pt_1 = [sol.x(1);sol.y(1);sol.z(1)] % First Solution Point
pt_2 = [sol.x(2);sol.y(2);sol.z(2)] % Second Solution Point
x = zeros(100,100);
y = zeros(100,100);
z = zeros(100,100);
for i=451:550
disp(['i=',num2str(i)])
for j=451:550
res = double(subs(pt_1,{alpha,beta},{(1145-i)*degree,(1145-j)*degree}));
x(i-450, j-450) = res(1);
y(i-450, j-450) = res(2);
z(i-450, j-450) = res(3);
end
end
disp('x=');
disp(x);
disp('y=');
disp(x);
disp('z=');
disp(x);
I would try
for i=1:100
k=num2str(i)
[a,b]=solve('100+a/2=173*cos(b)','sqrt(3)*a/2=173*sin(b)','a','b')
end
and then solve the equation