Disable Matlab symbolic rational approximation - matlab

Matlab Symbolic tool has a very annoying feature to me. It automatically convert to rational/decimal values.
Example 1
z = sym('z', 'real');
f = 3^(1/2)*z;
we get expected Matlab return f = 3^(1/2)*z
Example 2
z = sym('z', 'real');
f = 3^(1/3)*z;
Then I got crappy result f = (3247657313705851*z)/2251799813685248, not desired f=3^(1/3)*z
The reason for this can be found here. By default sym() use rational approximation to the numbers.
My question is, how to disable this feature? For example, how to get return f=3^(1/3)*z from the Example 2?

The documentation you link to tells you how to work around this by forcing numeric values to be computed symbolically. In this case, it's the 1/3 piece that can't be represented with sufficient precision in double, so you can do:
f = 3 ^ (sym(1)/sym(3)) * z;

Related

Definite integration using int command

Firstly, I'm quite new to Matlab.
I am currently trying to do a definite integral with respect to y of a particular function. The function that I want to integrate is
(note that the big parenthesis is multiplying with the first factor - I can't get the latex to not make it look like power)
I have tried plugging the above integral into Desmos and it worked as intended. My plan was to vary the value of x and y and will be using for loop via matlab.
However, after trying to use the int function to calculate the definite integral with the code as follow:
h = 5;
a = 2;
syms y
x = 3.8;
p = 2.*x.^2+2.*a.*y;
q = x.^2+y.^2;
r = x.^2+a.^2;
f = (-1./sqrt(1-(p.^2./(4.*q.*r)))).*(2.*sqrt(q).*sqrt(r).*2.*a-p.*2.*y.*sqrt(r)./sqrt(q))./(4.*q.*r);
theta = int(f,y,a+0.01,h) %the integral is undefined at y=2, hence the +0.01
the result is not quite as expected
theta =
int(-((8*461^(1/2)*(y^2 + 361/25)^(1/2))/5 - (461^(1/2)*y*(8*y + 1444/25))/(5*(y^2 + 361/25)^(1/2)))/((1 - (4*y + 722/25)^2/((1844*y^2)/25 + 665684/625))^(1/2)*((1844*y^2)/25 + 665684/625)), y, 21/10, 5)
After browsing through various posts, the common mistake is the undefined interval but the +0.01 should have fixed it. Any guidance on what went wrong is much appreciated.
The Definite Integrals example in the docs shows exactly this type of output when a closed form cannot be computed. You can approximate it numerically using vpa, i.e.
F = int(f,y,a,h);
theta = vpa(F);
Or you can do a numerical computation directly
theta = vpaintegral(f,y,a,h);
From the docs:
The vpaintegral function is faster and provides control over integration tolerances.

Solve equation with exponential term

I have the equation 1 = ((π r2)n) / n! ∙ e(-π r2)
I want to solve it using MATLAB. Is the following the correct code for doing this? The answer isn't clear to me.
n= 500;
A= 1000000;
d= n / A;
f= factorial( n );
solve (' 1 = ( d * pi * r^2 )^n / f . exp(- d * pi * r^2) ' , 'r')
The answer I get is:
Warning: The solutions are parametrized by the symbols:
k = Z_ intersect Dom::Interval([-(PI/2 -
Im(log(`fexp(-PI*d*r^2)`)/n)/2)/(PI*Re(1/n))], (PI/2 +
Im(log(`fexp(-PI*d*r^2)`)/n)/2)/(PI*Re(1/n)))
> In solve at 190
ans =
(fexp(-PI*d*r^2)^(1/n))^(1/2)/(pi^(1/2)*d^(1/2)*exp((pi*k*(2*i))/n)^(1/2))
-(fexp(-PI*d*r^2)^(1/n))^(1/2)/(pi^(1/2)*d^(1/2)*exp((pi*k*(2*i))/n)^(1/2))
You have several issues with your code.
1. First, you're evaluating some parts in floating-point. This isn't always bad as long as you know the solution will be exact. However, factorial(500) overflows to Inf. In fact, for factorial, anything bigger than 170 will overflow and any input bigger than 21 is potentially inexact because the result will be larger than flintmax. This calculation should be preformed symbolically via sym/factorial:
n = sym(500);
f = factorial(n);
which returns an integer approximately equal to 1.22e1134 for f.
2. You're using a period ('.') to specify multiplication. In MuPAD, upon which most of the symbolic math functions are based, a period is shorthand for concatenation.
Additionally, as is stated in the R2015a documentation (and possibly earlier):
String inputs will be removed in a future release. Use syms to declare the variables instead, and pass them as a comma-separated list or vector.
If you had not used a string, I don't think that it would have been possible for your command to get misinterpreted and return such a confusing result. Here is how you could use solve with symbolic variables:
syms r;
n = sym(500);
A = sym(1000000);
d = n/A;
s = solve(1==(d*sym(pi)*r^2)^n/factorial(n)*exp(-d*sym(pi)*r^2),r)
which, after several minutes, returns a 1,000-by-1 vector of solutions, all of which are complex. As #BenVoigt suggests, you can try the 'Real' option for solve. However, in R2015a at least, the four solutions returned in terms of lambertw don't appear to actually be real.
A couple things to note:
MATLAB is not using the values of A, d, and f from your workspace.
f . exp is not doing at all what you wanted, which was multiplication. It's instead becoming an unknown function fexp
Passing additional options of 'Real', true to solve gets rid of most of these extraneous conditions.
You probably should avoid calling the version of solve which accepts a string, and use the Symbolic Toolbox instead (syms 'r')

Numerical integration of symbolic differentiation - MATLAB

The following is a MATLAB problem.
Suppose I define an function f(x,y).
I want to calculate the partial derivative of f with respect to y, evaluated at a specific value of y, e.g., y=6. Finally, I want to integrate this new function (which is only a function of x) over a range of x.
As an example, this is what I have tried
syms x y;
f = #(x, y) x.*y.^2;
Df = subs(diff(f,y),y,2);
Int = integral(Df , 0 , 1),
but I get the following error.
Error using integral (line 82)
First input argument must be a function
handle.
Can anyone help me in writing this code?
To solve the problem, matlabFunction was required. The solution looks like this:
syms x y
f = #(x, y) x.*y.^2;
Df = matlabFunction(subs(diff(f,y),y,2));
Int = integral(Df , 0 , 1);
Keeping it all symbolic, using sym/int:
syms x y;
f = #(x, y) x.*y.^2;
Df = diff(f,y);
s = int(Df,x,0,1)
which returns y. You can substitute 2 in for y here or earlier as you did in your question. Not that this will give you an exact answer in this case with no floating-point error, as opposed to integral which calculated the integral numerically.
When Googling for functions in Matlab, make sure to pay attention what toolbox they are in and what classes (datatypes) they support for their arguments. In some cases there are overloaded versions with the same name, but in others, you may need to look around for a different method (or devise your own).

Matlab nchoosek got difference answer using int64 and sym

This is a question about the function nchoosek in Matlab.
I want to find nchoosek(54,25), which is the same as 54C25. Since the answer is about 10^15, I originally use int64. However the answer is wrong with respect to the symbolic one.
Input:
nchoosek(int64(54),int64(25))
nchoosek(sym(54),sym(25))
Output:
1683191473897753
1683191473897752
You can see that they differ by one. This is not really an urgent problem since I now use sym. However can someone tell me why this happens?
EDIT:
I am using R2013a.
I take a look at the nchoosek.m, and find that if the input are in int64, the code can be simplified into
function c = nchoosek2(v,k)
n = v; % rename v to be n. the algorithm is more readable this way.
classOut = 'int64';
nd = double(n);
kd = double(k);
nums = (nd-kd+1):nd;
dens = 1:kd;
nums = nums./dens; %%
c = round(prod(nums));
c = cast(c,classOut);
end
However, the outcome of int64(prod(nums./dens)) is different from prod(sym(nums)./sym(dens)) for me. Is this the same for everyone?
I don't have this problem on R2014a:
Numeric
>> n = int64(54);
>> k = int64(25);
>> nchoosek(n,k)
ans =
1683191473897752 % class(ans) == int64
Symbolic
>> nn = sym(n);
>> kk = sym(k);
>> nchoosek(nn,kk)
ans =
1683191473897752 % class(ans) == sym
% N!/((N-K)! K!)
>> factorial(nn) / (factorial(nn-kk) * factorial(kk))
ans =
1683191473897752 % class(ans) == sym
If you check the source code of the function edit nchoosek.m, you'll see it specifically handles the case of 64-bit integers using a separate algorithm. I won't reproduce the code here, but here are the highlights:
function c = nchoosek(v,k)
...
if int64type
% For 64-bit integers, use an algorithm that avoids
% converting to doubles
c = binCoef(n,k,classOut);
else
% Do the computation in doubles.
...
end
....
end
function c = binCoef(n,k,classOut)
% For integers, compute N!/((N-K)! K!) using prime factor cancellations
...
end
In 2013a this can be reproduced...
There is as #Amro shows a special case in nchoosek for classOut of int64 or unit64,
however in 2013a this is only applied when the answer is between
flintmax (with no argument) and
double(intmax(classOut)) + 2*eps(double(intmax(classOut)))
which for int64 gives 9007199254740992 & 9223372036854775808, which the solution does not lie between...
If the solution had fallen between these values it would be recalculated using the subfunction binCoef
for which the help states: For integers, compute N!/((N-K)! M!) using prime factor cancellations
The binCoef function would have produced the right answer for the given int64 inputs
In 2013a with these inputs binCoef is not called
Instead the "default" pascals triangle method is used in which:
Inputs are cast to double
The product of the vector ((n-k+1):n)./(1:k) is taken
this vector contains k double representations of fractions.
So what we have is almost certainly floating point error.
What can be done?
Two options I can see;
Make your own function based on the code in binCoef,
Modify nchoosek and remove && c >= flintmax from line 81
Removing this expression will force Matlab to use the more accurate integer based calculation for inputs of int64 and uint64 for any values within their precision. This will be slightly slower but will avoid floating point errors, which are rightfully unexpected when working with integer types.
Option one - should be fairly straight forward...
Option two - I recommend keeping an unchanged backup of the original function, or makeing a copy of the function with the modification and use that instead.

How do I make a function from a symbolic expression in MATLAB?

How can I make a function from a symbolic expression? For example, I have the following:
syms beta
n1,n2,m,aa= Constants
u = sqrt(n2-beta^2);
w = sqrt(beta^2-n1);
a = tan(u)/w+tanh(w)/u;
b = tanh(u)/w;
f = (a+b)*cos(aa*u+m*pi)+a-b*sin(aa*u+m*pi); %# The main expression
If I want to use f in a special program to find its zeroes, how can I convert f to a function? Or, what should I do to find the zeroes of f and such nested expressions?
You have a couple of options...
Option #1: Automatically generate a function
If you have version 4.9 (R2007b+) or later of the Symbolic Toolbox you can convert a symbolic expression to an anonymous function or a function M-file using the matlabFunction function. An example from the documentation:
>> syms x y
>> r = sqrt(x^2 + y^2);
>> ht = matlabFunction(sin(r)/r)
ht =
#(x,y)sin(sqrt(x.^2+y.^2)).*1./sqrt(x.^2+y.^2)
Option #2: Generate a function by hand
Since you've already written a set of symbolic equations, you can simply cut and paste part of that code into a function. Here's what your above example would look like:
function output = f(beta,n1,n2,m,aa)
u = sqrt(n2-beta.^2);
w = sqrt(beta.^2-n1);
a = tan(u)./w+tanh(w)./u;
b = tanh(u)./w;
output = (a+b).*cos(aa.*u+m.*pi)+(a-b).*sin(aa.*u+m.*pi);
end
When calling this function f you have to input the values of beta and the 4 constants and it will return the result of evaluating your main expression.
NOTE: Since you also mentioned wanting to find zeroes of f, you could try using the SOLVE function on your symbolic equation:
zeroValues = solve(f,'beta');
Someone has tagged this question with Matlab so I'll assume that you are concerned with solving the equation with Matlab. If you have a copy of the Matlab Symbolic toolbox you should be able to solve it directly as a previous respondent has suggested.
If not, then I suggest you write a Matlab m-file to evaluate your function f(). The pseudo-code you're already written will translate almost directly into lines of Matlab. As I read it your function f() is a function only of the variable beta since you indicate that n1,n2,m and a are all constants. I suggest that you plot the values of f(beta) for a range of values. The graph will indicate where the 0s of the function are and you can easily code up a bisection or similar algorithm to give you their values to your desired degree of accuracy.
If you broad intention is to have numeric values of certain symbolic expressions you have, for example, you have a larger program that generates symbolic expressions and you want to use these expression for numeric purposes, you can simply evaluate them using 'eval'. If their parameters have numeric values in the workspace, just use eval on your expression. For example,
syms beta
%n1,n2,m,aa= Constants
% values to exemplify
n1 = 1; n2 = 3; m = 1; aa = 5;
u = sqrt(n2-beta^2);
w = sqrt(beta^2-n1);
a = tan(u)/w+tanh(w)/u;
b = tanh(u)/w;
f = (a+b)*cos(aa*u+m*pi)+a-b*sin(aa*u+m*pi); %# The main expression
If beta has a value
beta = 1.5;
eval(beta)
This will calculate the value of f for a particular beta. Using it as a function. This solution will suit you in the scenario of using automatically generated symbolic expressions and will be interesting for fast testing with them. If you are writing a program to find zeros, it will be enough using eval(f) when you have to evaluate the function. When using a Matlab function to find zeros using anonymous function will be better, but you can also wrap the eval(f) inside a m-file.
If you're interested with just the answer for this specific equation, Try Wolfram Alpha, which will give you answers like:
alt text http://www4c.wolframalpha.com/Calculate/MSP/MSP642199013hbefb463a9000051gi6f4heeebfa7f?MSPStoreType=image/gif&s=15
If you want to solve this type of equation programatically, you probably need to use some software packages for symbolic algebra, like SymPy for python.
quoting the official documentation:
>>> from sympy import I, solve
>>> from sympy.abc import x, y
Solve a polynomial equation:
>>> solve(x**4-1, x)
[1, -1, -I, I]
Solve a linear system:
>>> solve((x+5*y-2, -3*x+6*y-15), x, y)
{x: -3, y: 1}