Indefinite integration with Matlab's Symbolic Toolbox - complex solution - matlab

I'm using Matlab 2014b. I've tried:
clear all
syms x real
assumeAlso(x>=5)
This returned:
ans =
[ 5 <= x, in(x, 'real')]
Then I tried:
int(sqrt(x^2-25)/x,x)
But this still returned a complex answer:
(x^2 - 25)^(1/2) - log(((x^2 - 25)^(1/2) + 5*i)/x)*5*i
I tried the simplify command, but still a complex answer. Now, this might be fixed in the latest version of Matlab. If so, can people let me know or offer a suggestion for getting the real answer?
The hand-calculated answer is sqrt(x^2-25)-5*asec(x/5)+C.

This behavior is present in R2017b, though when converted to floating point the imaginary components are different.
Why does this occur?
This occurs because Matlab's int function returns the full general solution when you ask for the indefinite integral. This solution is valid over the entire domain of of real values, including your restricted domain of x>=5.
With a bit of math you can show that the solution is always real for x>=5 (see complex logarithm). Or you can use more symbolic math via the isAlways function to show this:
syms x real
assume(x>=5)
y = int(sqrt(x^2-25)/x, x)
isAlways(imag(y)==0)
This returns true (logical 1). Unfortunately, Matlab's simplification routines appear to not be able to reduce this expression when assumptions are included. You might also submit this case to The MathWorks as a service request in case they'd consider improving the simplification for this and similar equations.
How can this be "fixed"?
If you want to get rid of the zero-valued imaginary part of the solution you can use sym/real:
real(y)
which returns 5*atan2(5, (x^2-25)^(1/2)) + (x^2-25)^(1/2).
Also, as #SardarUsama points out, when the full solution is converted to floating point (or variable precision) there will sometimes numeric imprecision when converting from exact symbolic form. Using the symbolic real form above should avoid this.

The answer is not really complex.
Take a look at this:
clear all; %To clear the conditions of x as real and >=5 (simple clear doesn't clear that)
syms x;
y = int(sqrt(x^2-25)/x, x)
which, as we know, gives:
y =
(x^2 - 25)^(1/2) - log(((x^2 - 25)^(1/2) + 5i)/x)*5i
Now put some real values of x≥5 to check what result it gives:
n = 1004; %We'll be putting 1000 values of x in y from 5 to 1004
yk = zeros(1000,1); %Preallocation
for k=5:n
yk(k-4) = subs(y,x,k); %Putting the value of x
end
Now let's check the imaginary part of the result we have:
>> imag(yk)
ans =
1.0e-70 *
0
0
0
0
0.028298997121333
0.028298997121333
0.028298997121333
%and so on...
Notice the multiplier 1e-70.
Let's check the maximum value of imaginary part in yk.
>> max(imag(yk))
ans =
1.131959884853339e-71
This implies that the imaginary part is extremely small and it is not a considerable amount to be worried about. Ideally it may be zero and it's coming due to imprecise calculations. Hence, it is safe to call your result real.

Related

Matlab symbolic

I am trying to compare two simple expressions using Matlab symbolic toolbox. For some reason, the code returns 0. Any idea ?
syms a b c
A = (a/b)^c
B = a^c/b^c
isequal(A,B)
It seems like MATLAB has a hard time telling that two expressions are the same when (potentially) fractional exponents are involved.
So, one solution, as suggested by Mikhail is to restrict the values of c to be only integers although, as discussed in the Math.SE question jodag posted, there is nothing wrong with fractional exponents in this case.
Hence, since this restriction to integers is not necessary for the statement to be true, another solution is to use simplify function on the expression for B but allowing it to run more simplification steps in order to get the most simplified expression.
syms a b c
A = (a/b)^c
B = a^c/b^c
isequal(A,simplify(B,'step',4))
Four steps is actually the smallest number that worked for me, but that could vary across versions of MATLAB I'm assuming. To be sure, I would include more, but for really large expressions, this could become computationally intensive, so some judgment is necessary. Note that, you could also use the 'Seconds' option to limit the amount of time allowed for simplification.
In general what you wrote isn't true, under the right "assumptions" it becomes true: for example, assuming c is an integer you can trick MATLAB into expanding A
clc; clear all;
syms a
syms b
syms c integer
A = (a/b)^c;
B = simplify((a^c)/(b^c));
disp(isequal(A,B));
disp(A);
disp(B);
1
a^c/b^c
a^c/b^c

fzero or fsolve ? differents results - Who is the correct ?

I have a function
b=2.02478;
g=3.45581;
s=0.6;
R=1;
p =#(r) 1 - (b./r).^2 - (g^-2)*((2/15)*(s/R)^9 *(1./(r - 1).^9 - 1./(r + 1).^9 - 9./(8*r).*(1./(r - 1).^8 - 1./(r + 1).^8)) -(s/R)^3 *(1./(r-1).^3 - 1./(r+1).^3 - 3./(2*r).*(1./(r-1).^2 - 1./(r+1).^2)));
options = optimset('Display','off');
tic
r2 = fzero(p,[1.001,100])
toc
tic
r3 = fsolve(p,[1.001,100],options)
toc
and the answer
r2 =
2.0198
Elapsed time is 0.002342 seconds.
r3 =
2.1648 2.2745
Elapsed time is 0.048991 seconds.
which is more confiable ? fzero returns different values than fsolve
You should always look at the exit flag (or output struct) of a function, especially when your result is not as expected.
This is what I get:
fzero(func,[1.00001,100]):
X = 4.9969
FVAL
EXITFLAG = 1 % fzero found a zero X.
OUTPUT.message = 'Zero found in the interval [1.00001, 100]'
fzero(func,1.1):
X = 1
FVAL = 8.2304e+136
EXITFLAG = -5 % fzero may have converged to a singular point.
OUTPUT.message = 'Current point x may be near a singular point. The interval [0.975549, 1.188] reduced to the requested tolerance and the function changes sign in the interval, but f(x) increased in magnitude as the interval reduced.'
The meaning of the exit flag is explained in the matlab documentation:
1 Function converged to a solution x.
-5 Algorithm might have converged to a singular point.
-6 fzero did not detect a sign change.
So, based on this information it is clear that the first one gives you the correct result.
Why does fzero fails
As documented in the manual, fzero calculates the zero by finding a sign change:
tries to find a point x where fun(x) = 0. This solution is where fun(x) changes sign—fzero cannot find a root of a function such as x^2.
Therefore, X = 1 is also a solution of your formulation as the sign changes at this location from +inf to -inf as can be seen on a plot:
Note that it is always a good idea to provide a search range if possible as mentioned in the manual:
Calling fzero with a finite interval guarantees fzero will return a value near a point where FUN changes sign.
Tip: Calling fzero with an interval (x0 with two elements) is often faster than calling it with a scalar x0.
Alternative: fsolve
Note that this method is developed for solving a system of multiple nonlinear equations. Therefore, it is not as efficient as fzero (~20x slower in your case). fzero uses gradient based methods (check the manual for more information), which may work better in certain situations, but may get stuck in a local extrema. In this case, the gradient of your function gives the correct direction as long as your initial value is larger than 1. So, for this specific function fsolve is somewhat more robust than fzero with a single initial value, i.e. fsolve(func, 1.1) returns the expected value.
Conclusion: In general, use fzero with a search range instead of an initial value if possible for a single variable and fsolve for multiple variables. If one method fails, you can try another method or another starting point.
As you can read in documentation:
The algorithm, which was originated by T. Dekker, uses a combination of bisection, secant, and inverse quadratic interpolation methods.
So, it is sensitive into the initial point and area which it is seeking for the solution. Hence, you have gotten different result for different initial value and scope.

Using SciPy's quad to get the principal value of an integral by integrating to just below and from just above the singular point

I am trying to compute the principal value of an integral (over s) of 1/((s - q02)*(s - q2)) on [Ecut, inf] with q02 < Ecut < q2. Doing the Principle value by hand (or Mathematica) one obtains the general result
ln((q2-Ecut)/(Ecut-q02)) / (q02 -q2)
In the specific example below this gives the result -1.58637*10^-11. One should also be able to get the same result by splitting the integral in two, integrating up to q2 - eps and then starting from q2 + eps, and then adding the two results (the divergences should cancel). By taking eps smaller and smaller one should recover the result above. When I implement this in scipi using quad however my result converges to the wrong result 6.04685e-11, as I show in the plot of eps vs integral result I include.
Why is quad doing this? even if I have eps = 0 it gives me this wrong result, when I would expect it to give me an error as the thing blows up...
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
q02 = 485124412.
Ecut = 17909665929.
q2 = 90000000000.
def integrand(s):
return 1/((s - q02)*(s - q2))
xx=[1.,0.1,0.01,0.001,0.0001,0.00001,0.000001,0.0000001,0.00000001,
0.000000001,0.0000000001,0.00000000001,0.]
integral = [0*y for y in xx]
i=0
for eps in xx:
ans1,err = quad(integrand, Ecut, q2 -eps )
ans2,err= quad(integrand, q2 + eps, np.inf)
integral[i] = ans1 + ans2
i=i+1
plt.semilogx(xx,integral,marker='.')
plt.show()
One should also be able to get the same result by splitting the integral in two, integrating up to q2 - eps and then starting from q2 + eps, and then adding the two results
Only if computations were perfectly accurate. In numerical practice, what you described is basically the worst thing one could do. You get two large integrals of opposite signs that very nearly cancel each other when added; what is left has more to do with the errors of integration than with actual value of the integral.
I notice you disregarded the error values err in your script, not even printing them out. Bad idea: they are of size 1e-10, which would already tell you that the final result with "something e-11" is junk.
The Computational Science question Numerical Principal Value Integration - Hilbert like addresses this issue. One of the approaches they indicate is to add the values of the integrand at the points symmetric about the singularity, before trying to integrate it. This requires taking the integral over a symmetric interval centered at the singularity q2 (that is, from Ecut to 2*q2-Ecut), and then adding the contribution of the integral from 2*q2-Ecut to infinity. This split makes sense anyway, because quad treats infinite limits very differently (using Fourier integration), which is yet another thing that will affect the way the singularity cancels out.
So, an implementation of this approach would be
ans1, err = quad(lambda s: integrand(s) + integrand(2*q2-s), Ecut, q2)
ans2, err = quad(integrand, 2*q2-Ecut, np.inf)
No eps is needed. However, the result is still off: it's about -2.5e-11. Turns out, the second integral is the culprit. Unfortunately, the Fourier integral approach doesn't seem to be effective here (or I didn't find a way to make it work). It turns out that providing a large, but finite value as the upper limit leads to a better result, especially if the option epsabs is also used, e.g. epsabs=1e-20.
Better yet, read the documentation of quad extra carefully and notice that it directly supports integrals with Cauchy weight 1/(s-q2), choosing an appropriate numerical method for them. This still requires a finite upper limit, and a small value of epsabs, but the result is pretty accurate:
quad(lambda s: 1/(s - q02), Ecut, 1e9*q2, weight='cauchy', wvar=q2, epsabs=1e-20)
returns -1.5863735715967363e-11, compared to exact value -1.5863735704856253e-11. Notice that the factor 1/(s-q2) does not appear in the integrand above, being relegated to the weight options.

MATLAB's Symbolic Math Fails to Solve a Simple Inequality

I have a simple inequality and MATLAB's Symbolic Math toolbox is doing something very strange. Here are the variables:
>> syms X ndot4B xiA ndot4A xiB
I'm trying to solve the following inequality (please do it yourself "on paper"):
>> solve(X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB > 0, xiA)
The answer is:
ans =
(X*ndot4A*xiB - 1)/(ndot4B - X*ndot4B)
But this is not correct. If instead I solve it as an equality:
>> solve(X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB, xiA)
The result is:
ans =
(X*ndot4A*xiB)/(ndot4B - X*ndot4B)
The above is correct (i.e., xiA has to be greater than the solution above). The difference is in the numerator. Maple gets it right (as it should). Any ideas on what may be going on? It's hard to believe that MATLAB would screw up on such simple calculation.
EDIT:
Based on horchler's answer, I tried solving the same inequality using assumptions on both MATLAB and Maple.
MATLAB:
Maple:
I still find MATLAB's answer very strange...
Your system is ill-defined. You (and perhaps Maple) are making some assumptions that aren't necessarily true or that are at least different from each other. When solving inequalities, it's best to use the 'ReturnConditions' option to see the full details of the solution. In your case:
syms X xiA ndot4B ndot4A xiB
s = solve(X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB > 0, xiA, 'ReturnConditions', true)
This returns a data structure:
xiA: [1x1 sym]
parameters: [1x1 sym]
conditions: [1x1 sym]
Now you'll see that there is an additional parameter (s.parameters is x) and set of conditions (s.conditions is X ~= 1 & ndot4B ~= 0 & 0 < x). The solution, s.xiA, is a function of the parameter:
-(x - X*ndot4A*xiB)/(ndot4B - X*ndot4B)
Because you are solving this with the strict inequality (> rather than >=), the parameter x can't actually be equal to zero to guarantee satisfying the inequality (Maple may treat the two cases the same, I'm not sure).
So why does Matlab's symbolic engine (not quite the same as the MuPAD environment) return (X*ndot4A*xiB - 1)/(ndot4B - X*ndot4B) when you don't ask for the return conditions? Firstly, this answer satisfies the inequality and is perfectly valid given that there is no information (assumptions) about the ranges of each variable. Rather than return an error or warning, it looks like Matlab just chose the first integer value of the parameter x that would satisfy the conditions, i.e., 1. It appears to treat the <= case similarly, but for some reason does not choose 0 for x (which would match the ==). I suggest filing a service request if you want to try to ask The MathWorks why this is and if it might be a bug of some sort.
I also recommend learning about and using assumptions when working with solve.
solve's answer is correct. You simply need some positive value in the numerator to satisfy the inequality. It can be any value, hence solve introduces a parameter.
You can verify your proposed answer and solve's answer as:
syms X ndot4B xiA ndot4A xiB
eqn = X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB > 0;
trySol = (X*ndot4A*xiB)/(ndot4B - X*ndot4B); % let's try the proposed answer
tryCondition = subs(eqn,xiA,trySol); % substitute the answer to get the condition
isAlways(tryCondition) % check if the condition holds?
ans =
logical
0
The condition doesn't hold. Now try solve's answer with the same steps:
trySol = (X*ndot4A*xiB - 1)/(ndot4B - X*ndot4B);
tryCondition = subs(eqn,xiA,trySol);
isAlways(tryCondition)
ans =
logical
1
This answer is correct. You can check on paper yourself by substituting these two values for xiA. You just need some positive value in the numerator to satisfy the > inequality. For example, even using eps instead of 1 will work:
trySol = (X*ndot4A*xiB - eps)/(ndot4B - X*ndot4B);
isAlways(subs(eqn,xiA,trySol))
ans =
logical
1
As horchler pointed out, if you change the > to ==, then you don't need the positive value.
solve introduces assumptions, X~=1 and ndot4B~=0, because when you divide both sides of an inequality by a constant, then that constant cannot be 0.
Hope this helps.

Unable to code non linear equation in MATLAB R2013a - MATLAB giving warning message

I wanted to solve the following equation in MATLAB R2013a using the Symbolic Math Toolbox.
(y/x)-(((1+r)^n)-1)/r=0 where y,x and n>3 are given and r is the dependent variable
I tried myself & coded as follows:
f=solve('(y/x)-(((1+r)^n)-1)/r','r')
but as the solution for r is not exact i.e. it is converging on successive iterations hence MATLAB is giving a warning output with the message
Warning: Explicit solution could not be found.
f =
[ empty sym ]
How do I code this?
There are an infinite number of solutions to this for an unspecified value of n > 3 and unknown r. I hope that it's pretty clear why – it's effectively asking for a greater and greater number of roots of (1+r)^n. You can find solutions for fixed values of n, however. Note that as n becomes larger there are more and more solutions and of course some of them are complex. I'm going to assume that you're only interested in real values of r. You can use solve and symbolic math for n = 4, n = 5, and n = 6 (for n = 6, the solution may not be in a convenient form):
y = 441361;
x = 66990;
n = 5;
syms r;
rsol = solve(y/x-((1+r)^n-1)/r==0,r,'IgnoreAnalyticConstraints',true)
double(rsol)
However, the question is "do you need all the solutions or just a particular solution for a given value of n"? If you just need a particular solution, you shouldn't be using symbolic math at all as it's slower and has practical issues like the ones you're experiencing. You can instead just use a numerical approach to find a zero of the equation that is near a specified initial guess. fzero is the standard function for solving this sort of problem in a single variable:
y = 441361;
x = 66990;
n = 5;
f = #(r)y/x-((1+r).^n-1)./r;
r0 = 1;
rsol = fzero(f,r0)
You'll see that the value returned is the same as one of the solutions from the symbolic solution above. If you adjust the initial guess r0 (say r0 = -3), it will return the other solution. When using numeric approaches in cases when there are multiple solutions, if you want specific solutions you'll need to know about the behavior of your function and you'll need to add some clever extra code to choose initial guesses.
I think you forgot to define n as well.
f=solve('(y/x)-(((1+r)^n)-1)/r=0','n-3>0','r','n')
Should solve your problem :)