how drop near zero terms Matlab symbolic - matlab

I'm doing some symbolic matrix manipulations with complex value matrices. Some of my results are as below.
Zaa*(1 + 3i/36028797018963968) + Zab*(1 + 3i/36028797018963968)
Is there a way to tell Matlab to ignore those near zero imaginary results so the answer is reported simply as,
Zaa + Zab
UPDATE 1: To provide the full background on how I am getting these results. I am doing a calculation power electrical engineers call the similarity transformation. It is used in symmetrical component analysis of power system faults and involves a complex transformation matrix and complex impedance values (the later are my symbolic variables Zaa, Zab etc.).
Similarity transformation:
Where A is the 3x3 shown below and
So, the full transformation calculation looks like this (the 1/3 scale factor comes from inverting A),
Here is my Matlab code (requires Symbolic Toolbox)
syms Zaa Zab Zac Zba Zbb Zbc Zca Zcb Zcc
Z = [Zaa Zab Zac; Zba Zbb Zbc; Zca Zcb Zcc]
a = -1/2+sqrt(3)/2*1i
A = [1 1 1; 1 a^2 a; 1 a a^2]
Z012 = inv(A)*Z*A
Final Update: After #holcher solved my problem I thought I'd post the finished code.
syms Zaa Zab Zac Zba Zbb Zbc Zca Zcb Zcc
Z = [Zaa Zab Zac; Zba Zbb Zbc; Zca Zcb Zcc]
a = -1/2+sqrt(sym(3))/2*1i
A = [1 1 1; 1 a^2 a; 1 a a^2]
Z012 = inv(A)*Z*A
vpa(Z012,2)
p.s. The parallel question I had regarding solving this in Octave was also answered but required slightly different code. This final code runs in both Matlab & Octave.

First, why is this happening? It appears that you are mixing floating point values in with your symbolic math. Most numerical values do not have exact representations in floating point, resulting in small remainder values showing as in this case. The value 3/36028797018963968 is equal to (3/8)*eps. There are a few workarounds that may help you:
You can try representing parameters as symbolic variables and substituting in the floating point values later in your code via subs.
You can take care in how you convert floating point values to symbolic values. See this answer for more including a simple example of when this can occur. You might also take a look at the numeric conversion flag options for the sym function.
Consider using assumptions to restrict the domain of applicable symbolic variables to be real-valued if that is the case (Matlab symbolic variables are complex by default – this is why you will likely get a more complicated result if you call real or imag on your expression than you may expect). See assumptions, assume, and the options for syms.
Try calling simplify on a symbolic result prior to converting it to variable precision or floating point. The idea here is to possibly minimize mathematical operations that could contribute to numerical issues.
If none of those refactoring approaches work, you will need to write a function that evaluates your symbolic expression with a tolerance you specify for what you consider to be zero. This is non-trivial to implement in a general sense and is further complicated when working in the complex-valued domain.

Related

What is the fastest method for solving exp(ax)-ax+c=0 for x in matlab

What is the least computational time consuming way to solve in Matlab the equation:
exp(ax)-ax+c=0
where a and c are constants and x is the value I'm trying to find?
Currently I am using the in built solver function, and I know the solution is single valued, but it is just taking longer than I would like.
Just wanting something to run more quickly is insufficient for that to happen.
And, sorry, but if fzero is not fast enough then you won't do much better for a general root finding tool.
If you aren't using fzero, then why not? After all, that IS the built-in solver you did not name. (BE EXPLICIT! Otherwise we must guess.) Perhaps you are using solve, from the symbolic toolbox. It will be more slow, since it is a symbolic tool.
Having said the above, I might point out that you might be able to improve by recognizing that this is really a problem with a single parameter, c. That is, transform the problem to solving
exp(y) - y + c = 0
where
y = ax
Once you know the value of y, divide by a to get x.
Of course, this way of looking at the problem makes it obvious that you have made an incorrect statement, that the solution is single valued. There are TWO solutions for any negative value of c less than -1. When c = -1, the solution is unique, and for c greater than -1, no solutions exist in real numbers. (If you allow complex results, then there will be solutions there too.)
So if you MUST solve the above problem frequently and fzero was inadequate, then I would consider a spline model, where I had precomputed solutions to the problem for a sufficient number of distinct values of c. Interpolate that spline model to get a predicted value of y for any c.
If I needed more accuracy, I might take a single Newton step from that point.
In the event that you can use the Lambert W function, then solve actually does give us a solution for the general problem. (As you see, I am just guessing what you are trying to solve this with, and what are your goals. Explicit questions help the person trying to help you.)
solve('exp(y) - y + c')
ans =
c - lambertw(0, -exp(c))
The zero first argument to lambertw yields the negative solution. In fact, we can use lambertw to give us both the positive and negative real solutions for any c no larger than -1.
X = #(c) c - lambertw([0 -1],-exp(c));
X(-1.1)
ans =
-0.48318 0.41622
X(-2)
ans =
-1.8414 1.1462
Solving your system symbolically
syms a c x;
fx0 = solve(exp(a*x)-a*x+c==0,x)
which results in
fx0 =
(c - lambertw(0, -exp(c)))/a
As #woodchips pointed out, the Lambert W function has two primary branches, W0 and W−1. The solution given is with respect to the upper (or principal) branch, denoted W0, your equation actually has an infinite number of complex solutions for Wk (the W0 and W−1 solutions are real if c is in [−∞, 0]). In Matlab, lambertw is only implemented for symbolic inputs and thus is very slow method of solving your equation if you're interested in numerical (double precision) solutions.
If you wish to solve such equations numerically in an efficient manner, you might look at Corless, et al. 1996. But, as long as your parameter c is in [−∞, 0], i.e., -exp(c) in [−1/e, 0] and you're interested in the W0 branch, you can use the Matlab code that I wrote to answer a similar question at Math.StackExchange. This code should be much much more efficient that using a naïve approach with fzero.
If your values of c are not in [−∞, 0] or you want the solution corresponding to a different branch, then your solution may be complex-valued and you won't be able to use the simple code I linked to above. In that case, you can more fully implement the function by reading the Corless, et al. 1996 paper or you can try converting the Lambert W to a Wright ω function: W0(z) = ω(log(z)), W−1(z) = ω(log(z)−2πi). In your case, using Matlab's wrightOmega, the W0 branch corresponds to:
fx0 =
(c - wrightOmega(log(-exp(c))))/a
and the W−1 branch to:
fxm1 =
(c - wrightOmega(log(-exp(c))-2*sym(pi)*1i))/a
If c is real, then the above reduces to
fx0 =
(c - wrightOmega(c+sym(pi)*1i))/a
and
fxm1 =
(c - wrightOmega(c-sym(pi)*1i))/a
Matlab's wrightOmega function is also symbolic only, but I have written a double precision implementation (based on Lawrence, et al. 2012) that you can find on my GitHub here and that is 3+ orders of magnitude faster than evaluating the function symbolically. As your problem is technically in terms of a Lambert W, it may be more efficient, and possibly more numerically accurate, to implement that more complicated function for the regime of interest (this is due to the log transformation and the extra evaluation of a complex log). But feel free to test.

Matlab recursive curve fitting with custom equations

I have a curve IxV. I also have an equation that I want to fit in this IxV curve, so I can adjust its constants. It is given by:
I = I01(exp((V-R*I)/(n1*vth))-1)+I02(exp((V-R*I)/(n2*vth))-1)
vth and R are constants already known, so I only want to achieve I01, I02, n1, n2. The problem is: as you can see, I is dependent on itself. I was trying to use the curve fitting toolbox, but it doesn't seem to work on recursive equations.
Is there a way to make the curve fitting toolbox work on this? And if there isn't, what can I do?
Assuming that I01 and I02 are variables and not functions, then you should set the problem up like this:
a0 = [I01 I02 n1 n2];
MinFun = #(a) abs(a(1)*(exp(V-R*I)/(a(3)*vth))-1) + a(2)*(exp((V-R*I)/a(4)*vth))-1) - I);
aout = fminsearch(a0,MinFun);
By subtracting I and taking the absolute value, the point where both sides are equal will be the point where MinFun is zero (minimized).
No, the CFTB cannot fit such recursively defined functions. And errors in I, since the true value of I is unknown for any point, will create a kind of errors in variables problem. All you have are the "measured" values for I.
The problem of errors in I MAY be serious, since any errors in I, or lack of fit, noise, model problems, etc., will be used in the expression itself. Then you exponentiate these inaccurate values, potentially casing a mess.
You may be able to use an iterative approach. Thus something like
% 0. Initialize I_pred
I_pred = I;
% 1. Estimate the values of your coefficients, for this model:
% (The curve fitting toolbox CAN solve this problem, given I_pred)
I = I01(exp((V-R*I_pred)/(n1*vth))-1)+I02(exp((V-R*I_pred)/(n2*vth))-1)
% 2. Generate new predictions for I_pred
I_pred = I01(exp((V-R*I_pred)/(n1*vth))-1)+I02(exp((V-R*I_pred)/(n2*vth))-1)
% Repeat steps 1 and 2 until the parameters from the CFTB stabilize.
The above pseudo-code will work only if your starting values are good, and there are not large errors/noise in the model/data. Even on a good day, the above approach may not converge well. But I see little hope otherwise.

Why is Matlab saving values as symbolic variables with massive fractions instead of decimal approximations?

I'm currently working on a rudimentary optimization algorithm in Matlab, and I'm running into issues with Matlab saving variables at ridiculous precision. Within a few iterations the variables are so massive that it's actually triggering some kind of infinite loop in sym.m.
Here's the line of code that's starting it all:
SLine = (m * (X - P(1))) + P(2);
Where P = [2,2] and m = 1.2595. When I type this line of code into the command line manually, SLine is saved as the symbolic expression (2519*X)/2000 - 519/1000. I'm not sure why it isn't using a decimal approximation, but at least these fractions have the correct value. When this line of code runs in my program, however, it saves SLine as the expression (2836078626493975*X)/2251799813685248 - 584278812808727/1125899906842624, which when divided out isn't even precise to four decimals. These massive fractions are getting carried through my program, growing with each new line of code, and causing it to grind to a halt.
Does anyone have any idea why Matlab is behaving in this way? Is there a way to specify what precision it should use while performing calculations? Thanks for any help you can provide.
You've told us what m and P are, but what is X? X is apparently a symbolic variable. So further computations are all done symbolically.
Welcome to the Joys of Symbolic Computing!
Most Symbolic Algebra systems represent numbers as rationals, $(p,q) = \frac{p}{q}$, and perform rational arithmetic operations (+,-,*,/) on these numbers, which produce rational results. Generally, these results are exact (also called infinite precision).
It is well-known that the sizes of the rationals generated by rationals operations on rationals grow exponentially. Hence, if you try to solve a realistic problem with any Symbolic Algebra system, you eventually run out of space or time.
Here is the last word on this topic, where Nick Trefethen FRS shows why floating point arithmetic is absolutely vital for solving realistic numeric problems.
http://people.maths.ox.ac.uk/trefethen/publication/PDF/2007_123.pdf
Try this in Matlab:
function xnew = NewtonSym(xstart,niters);
% Symbolic Newton on simple polynomial
% Derek O'Connor 2 Dec 2012. derekroconnor#eircom.net
x = sym(xstart,'f');
for iter = 1:niters
xnew = x - (x^5-2*x^4-3*x^3+3*x^2-2*x-1)/...
(5*x^4-8*x^3-9*x^2+6*x-2);
x = xnew;
end
function xnew = TestNewtonSym(maxits);
% Test the running time of Symbolic Newton
% Derek O'Connor 2 Dec 2012.
time=zeros(maxits,1);
for niters=1:maxits
xstart=0;
tic;
xnew = NewtonSym(xstart,niters);
time(niters,1)=toc;
end;
semilogy((1:maxits)',time)
So, from MATLAB reference documentation on Symbolic computations, the symbolic representation will always be in exact rational form, as opposed to decimal approximation of a floating-point number [1]. The reason this is done, apparently, is to "to help avoid rounding errors and representation errors" [2].
The exact representation is something that cannot be overcome by just doing symbolic arithmetic. However, you can use Variable-Precision Arithmetic (vpa) in Matlab to get the same precision [3].
For example
>> sym(pi)
ans =
0
>> vpa(sym(pi))
ans =
3.1415926535897932384626433832795
References
[1] http://www.mathworks.com/help/symbolic/create-symbolic-numbers-variables-and-expressions.html
[2]https://en.wikibooks.org/wiki/MATLAB_Programming/Advanced_Topics/Toolboxes_and_Extensions/Symbolic_Toolbox
[3]http://www.mathworks.com/help/symbolic/vpa.html

Double integral in MATLAB

I'm trying to find the power in an aperture from a Gaussian beam, where the aperture is offset from the beam center. The solution is the following equation (reference) (sorry, no LaTeX here):
Wz is a constant, along with a and r. I'm not sure how I can do something like this with MATLAB. Does anyone have a suggestion? I know there's a dblquad() function, but it assumes that the limits of integration are fixed, and not dependent on each other.
Using a bit of mathematical footwork, you could reduce the double integral to a single one (albeit containing the error function) which should be easier to calculate numerically in MATLAB:
(With reservation for errors; check the calculations yourself if possible.)
It turns out that more recent versions of MATLAB now have a quad2d() function, which does a 2d integral over a surface. Example 2 on the reference page details an example of doing this type of integration.
My code ended up looking something like this:
powerIntegral = #(x,y) 2/(pi*W^2)*exp(-2*((x - offsetDist).^2 + y.^2)/(W^2));
ymin = #(x) -sqrt(radius.^2 - x.^2);
ymax = #(x) sqrt(radius.^2 - x.^2);
powerRatioGaussian = quad2d(powerIntegral,-radius,radius,ymin,ymax);
Pretty nifty. Thanks for the help.
I am not sure, but I think that the symbolic toolbox can help you here. It is suited for this kind of problems. You can define your variables as symbolic vars using the syms command, and compute the integral symbolically. Then, you can assign the variables values and find the actual value.
Disclaimer : I have never actually used it myself.
Generally speaking, for numeric integration, you can transform an integral with dependent boundary conditions to one with independent boundaries by multiplying by a function that is 1 if you are inside the original boundary and 0 if you are outside. Then take your limits to be a square that contains your original conditions. In other words here you would multiply by
g(x,y) = ((x^2 + y^2) < a^2)
and your limits would be -a
You have to be a little careful about the continuity assumptions in your integration method, but you should be OK unless something is very weird. You can always check by changing your cell size and making sure the computed integral value doesn't change.
In this particular case, you could also make the transformation from cartesian to polar coordinates;
x = rcos(t)
y = rsin(t)
dxdy = rdrdt
Then your limits of integration would be r from 0 to a and t from 0 to 2*pi

How to overcome singularities in numerical integration (in Matlab or Mathematica)

I want to numerically integrate the following:
where
and a, b and β are constants which for simplicity, can all be set to 1.
Neither Matlab using dblquad, nor Mathematica using NIntegrate can deal with the singularity created by the denominator. Since it's a double integral, I can't specify where the singularity is in Mathematica.
I'm sure that it is not infinite since this integral is based in perturbation theory and without the
has been found before (just not by me so I don't know how it's done).
Any ideas?
(1) It would be helpful if you provide the explicit code you use. That way others (read: me) need not code it up separately.
(2) If the integral exists, it has to be zero. This is because you negate the n(y)-n(x) factor when you swap x and y but keep the rest the same. Yet the integration range symmetry means that amounts to just renaming your variables, hence it must stay the same.
(3) Here is some code that shows it will be zero, at least if we zero out the singular part and a small band around it.
a = 1;
b = 1;
beta = 1;
eps[x_] := 2*(a-b*Cos[x])
n[x_] := 1/(1+Exp[beta*eps[x]])
delta = .001;
pw[x_,y_] := Piecewise[{{1,Abs[Abs[x]-Abs[y]]>delta}}, 0]
We add 1 to the integrand just to avoid accuracy issues with results that are near zero.
NIntegrate[1+Cos[(x+y)/2]^2*(n[x]-n[y])/(eps[x]-eps[y])^2*pw[Cos[x],Cos[y]],
{x,-Pi,Pi}, {y,-Pi,Pi}] / (4*Pi^2)
I get the result below.
NIntegrate::slwcon:
Numerical integration converging too slowly; suspect one of the following:
singularity, value of the integration is 0, highly oscillatory integrand,
or WorkingPrecision too small.
NIntegrate::eincr:
The global error of the strategy GlobalAdaptive has increased more than
2000 times. The global error is expected to decrease monotonically after a
number of integrand evaluations. Suspect one of the following: the
working precision is insufficient for the specified precision goal; the
integrand is highly oscillatory or it is not a (piecewise) smooth
function; or the true value of the integral is 0. Increasing the value of
the GlobalAdaptive option MaxErrorIncreases might lead to a convergent
numerical integration. NIntegrate obtained 39.4791 and 0.459541
for the integral and error estimates.
Out[24]= 1.00002
This is a good indication that the unadulterated result will be zero.
(4) Substituting cx for cos(x) and cy for cos(y), and removing extraneous factors for purposes of convergence assessment, gives the expression below.
((1 + E^(2*(1 - cx)))^(-1) - (1 + E^(2*(1 - cy)))^(-1))/
(2*(1 - cx) - 2*(1 - cy))^2
A series expansion in cy, centered at cx, indicates a pole of order 1. So it does appear to be a singular integral.
Daniel Lichtblau
The integral looks like a Cauchy Principal Value type integral (i.e. it has a strong singularity). That's why you can't apply standard quadrature techniques.
Have you tried PrincipalValue->True in Mathematica's Integrate?
In addition to Daniel's observation about integrating an odd integrand over a symmetric range (so that symmetry indicates the result should be zero), you can also do this to understand its convergence better (I'll use latex, writing this out with pen and paper should make it easier to read; it took a lot longer to write than to do, it's not that complicated):
First, epsilon(x)-\epsilon(y)\propto\cos(y)-\cos(x)=2\sin(\xi_+)\sin(\xi_-) where I have defined \xi_\pm=(x\pm y)/2 (so I've rotated the axes by pi/4). The region of integration then is \xi_+ between \pi/\sqrt{2} and -\pi/\sqrt{2} and \xi_- between \pm(\pi/\sqrt{2}-\xi_-). Then the integrand takes the form \frac{1}{\sin^2(\xi_-)\sin^2(\xi_+)} times terms with no divergences. So, evidently, there are second-order poles, and this isn't convergent as presented.
Perhaps you could email the persons who obtained an answer with the cos term and ask what precisely it is they did. Perhaps there's a physical regularisation procedure being employed. Or you could have given more information on the physical origin of this (some sort of second order perturbation theory for some sort of bosonic system?), had that not been off-topic here...
May be I am missing something here, but the integrand
f[x,y]=Cos^2[(x+y)/2]*(n[x]-n[y])/(eps[x]-eps[y]) with n[x]=1/(1+Exp[Beta*eps[x]]) and eps[x]=2(a-b*Cos[x]) is indeed a symmetric function in x and y: f[x,-y]= f[-x,y]=f[x,y].
Therefore its integral over any domain [-u,u]x[-v,v] is zero. No numerical integration seems to be needed here. The result is just zero.