Logical indexing and double precision numbers - matlab

I am trying to solve a non-linear system of equations using the Newton-Raphson iterative method, and in order to explore the parameter space of my variables, it is useful to store the previous solutions and use them as my first initial guess so that I stay in the basin of attraction.
I currently save my solutions in a structure array that I store in a .mat file, in about this way:
load('solutions.mat','sol');
str = struct('a',Param1,'b',Param2,'solution',SolutionVector);
sol=[sol;str];
save('solutions.mat','sol');
Now, I do another run, in which I need the above solution for different parameters NewParam1 and NewParam2. If Param1 = NewParam1-deltaParam1, and Param2 = NewParam2 - deltaParam2, then
load('solutions.mat','sol');
index = [sol.a]== NewParam1 - deltaParam1 & [sol.b]== NewParam2 - deltaParam2;
% logical index to find solution from first block
SolutionVector = sol(index).solution;
I sometimes get an error message saying that no such solution exists. The problem lies in the double precisions of my parameters, since 2-1 ~= 1 can happen in Matlab, but I can't seem to find an alternative way to achieve the same result. I have tried changing the numerical parameters to strings in the saving process, but then I ran into problems with logical indexing with strings.
Ideally, I would like to avoid multiplying my parameters by a power of 10 to make them integers as this will make the code quite messy to understand due to the number of parameters. Other than that, any help will be greatly appreciated. Thanks!

You should never use == when comparing double precision numbers in MATLAB. The reason is, as you state in the the question, that some numbers can't be represented precisely using binary numbers the same way 1/3 can't be written precisely using decimal numbers.
What you should do is something like this:
index = abs([sol.a] - (NewParam1 - deltaParam1)) < 1e-10 & ...
abs([sol.b] - (NewParam2 - deltaParam2)) < 1e-10;
I actually recommend not using eps, as it's so small that it might actually fail in some situations. You can however use a smaller number than 1e-10 if you need a very high level of accuracy (but how often do we work with numbers less than 1e-10)?

Related

How to force MATLAB to not compute as Inf

I am trying to work through some code that I wrote and one specific line is giving me problems in MATLAB:
Ts = (1+(DatesMod.*Bs)./VolMod).^(VolMod);
VolMod is an array with values on the order of 10^8, DatesMod has a range of values between 700,000 and 740,000, and Bs has a range of values between 0 and 100. Note that this function is mathematically similar to doing lim(n->Inf) (1+B*Dates/n)^n. I understand that this primarily has to do with the methods of allocating numbers on the computer. Is there a clever way I can force it to compute the actual value instead of returning Inf for every value?
Thanks in advance.
Note that the limit
lim(n->Inf) (1+B*Dates/n)^n = exp(B*Dates)
and that exp will overflow to Inf once the argument is greater than 709.9, so there is no real way to compute Ts exactly without arbitrary precision arithmetic.
The best option is probably work in log-precision, e.g. instead of Ts you work with logTs
logTs = VolMod .* log1p((DatesMod.*Bs)./VolMod)
You would then need to rewrite any subsequent expressions to use this without explicitly computing exp(logTs) (as that will overflow).

Matlab not accepting whole number as index

I am using a while loop with an index t starting from 1 and increasing with each loop.
I'm having problems with this index in the following bit of code within the loop:
dt = 100000^(-1);
t = 1;
equi = false;
while equi==false
***some code that populates the arrays S(t) and I(t)***
t=t+1;
if (t>2/dt)
n = [S(t) I(t)];
np = [S(t-1/dt) I(t-1/dt)];
if sum((n-np).^2)<1e-5
equi=true;
end
end
First, the code in the "if" statement is accessed at t==200000 instead of at t==200001.
Second, the expression S(t-1/dt) results in the error message "Subscript indices must either be real positive integers or logicals", even though (t-1/dt) is whole and equals 1.0000e+005 .
I guess I can solve this using "round", but this worked before and suddenly doesn't work and I'd like to figure out why.
Thanks!
the expression S(t-1/dt) results in the error message "Subscript indices must either be real positive integers or logicals", even though (t-1/dt) is whole and equals 1.0000e+005
Is it really? ;)
mod(200000 - 1/dt, 1)
%ans = 1.455191522836685e-11
Your index is not an integer. This is one of the things to be aware of when working with floating point arithmetic. I suggest reading this excellent resource: "What every computer scientist should know about floating-point Arithmetic".
You can either use round as you did, or store 1/dt as a separate variable (many options exist).
Matlab is lying to you. You're running into floating point inaccuracies and Matlab does not have an honest printing policy. Try printing the numbers with full precision:
dt = 100000^(-1);
t = 200000;
fprintf('2/dt == %.12f\n',2/dt) % 199999.999999999971
fprintf('t - 1/dt == %.12f\n',t - 1/dt) % 100000.000000000015
While powers of 10 are very nice for us to type and read, 1e-5 (your dt) cannot be represented exactly as a floating point number. That's why your resulting calculations aren't coming out as even integers.
The statement
S(t-1/dt)
can be replaced by
S(uint32(t-1/dt))
And similarly for I.
Also you might want to save 1/dt hardcoded as 100000 as suggested above.
I reckon this will improve the comparison.

MATLAB - replace zeros in matrix with small number

I have a matrix with some elements going to zero. This is a problem for me in consequent operations (taking log, etc). Is there a way to quickly replace zero elements in a matrix with a input of my choice. Quickly - meaning, without a loop.
The direct answer is:
M(M == 0) = realmin;
which does exactly what you ask for, replacing zeros with a small number. See that this does an implicit search for the zeros in a vectorized way. No loops are required. (This is a MATLAB way, avoiding those explicit and slow loops.)
Or, you could use max, since negative numbers are never an issue. So
M = max(M,realmin);
will also work. Again, this is a vectorized solution. I'm not positive which one is faster without a careful test, but either will surely be acceptable.
Note that I've used realmin here instead of eps, since it is as small as you can realistically get in a double precision number. But use whatever small number makes sense to you.
log10(realmin)
ans =
 -307.6527
Compare that to eps.
log10(eps)
ans =
-15.6536
Sure--where A is your matrix,
A(A==0) = my_small_number;
Assume your matrix is called A
A(A==0) = eps;

Mean of Very Small Values

I'm trying to compute the log of the mean of some very small values. For the current data set, the extreme points are
log_a=-1.6430e+03;
log_b=-3.8278e+03;
So in effect I want to compute (a+b) / 2, or log((a+b)/2) since I know (a+b)/2 is too small to store as a double.
I considered trying to pad everything by a constant, so that instead of storing log_a I'd store log_a+c, but it seems that aand b are far enough apart that in order to pad log_b enough to make exp(log_b+c) computable, I'd end up making exp(log_a+c) too large.
Am I missing some obvious way to go about this computation? As far as I know MATLAB won't let me use anything but double precision, so I'm stumped as to how I can do this simple computation.
EDIT: To clarify: I can compute the exact answer for these specific values. For other runs of the algorithm, the values will be different and might be closer together. So far there have been some good suggestions for approximations; if an exact solution isn't practical, are there any other approximations for more general numbers/magnitudes of values?
Mystical has the right idea but for a more general solution that gives you the log of the arithmetic mean of a vector log_v of numbers already in the log domain use:
max_log = max(log_v);
logsum = max_log + log(sum(exp(log_v-max_log)));
logmean = logsum - log(length(log_v));
This is a common problem in statistical machine learning, so if you do a Google search for logsum.m you'll find a few different versions of MATLAB functions that researchers have written for this purpose. For example, here's a Github link to a version that uses the same calling conventions as sum.
Well, exp(log_b) is so much smaller than exp(log_a) that you can completely ignore that term and still get the correct answer with respect to double-precision:
exp(log_a) = 2.845550077506*10^-714
exp(log_b) = 4.05118588390*10^-1663
If you are actually trying to compute (exp(log_a) + exp(log_b)) / 2, the answer would underflow to zero anyways. So it wouldn't really matter unless you're trying to take another logarithm at the end.
If you're trying compute:
log((exp(log_a) + exp(log_b)) / 2)
Your best bet is to examine the difference between log_a and log_b. If the difference is large, then simply take the final value as equal to the larger term - log(2) since the smaller term will be small enough to completely vanish.
EDIT:
So your final algorithm could look like this:
Check the magnitudes. If abs(log_a - log_b) > 800. Return max(log_a,log(b)) - log(2).
Check either magnitude (they will be close together at this point.). If it is much larger or smaller than 1, add/subtract a constant from both log_a and log_b.
Perform the calculation.
If the values were scaled in step 2. Scale the result back.
EDIT 2:
Here's an even better solution:
if (log_a > log_b)
return log_a + log(1 + exp(log_b - log_a)) - log(2)
else
return log_b + log(1 + exp(log_a - log_b)) - log(2)
This will work if log_a and log_b are not too large or are negative.
Well, if you don't like my previous suggestion of completely changing platforms and are looking for an approximation, why not just use the geometric mean (exp((log_a+log_b)/2) instead?
Use http://wolframalpha.com . For example, as discussed by Mysticial, your calculation of
log(exp(-1.6430e+03) + exp(-3.8278e+03)/2) is approximately equal to log_a. More precisely it equals...
1642.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999288154175193167154874243862288962865800888654829363675488466381404578225092913407982036991983506370017587380105049077722517705727311433458060227246074261903850589008701929721367650576354241270720062760800558681236724831345952032973775644175750495894596292205385323394564549904750849335403418234531787942293155499938538026848481952030717783105220543888597195156662520697417952130625416040662694927878196360733032741542418365527213770518383992577797346467266676866552563022498785887306273550235307330535082355570343750317349638125974233837177558240980392298326807001406291035229026016040567173260205109683449441154277953394697235601979288239733693137185710713089424316870093563207034737497769711306780243623361236030692934897720786516684985651633787662244416960982457075265287065358586526093347161275192566468776617613339812566918101457823704547101340270795298909954224594...

Numerical problems in Matlab: Same input, same code -> different output?

I am experiencing problems when I compare results from different runs of my Matlab software with the same input. To narrow the problem, I did the following:
save all relevant variables using Matlab's save() method
call a method which calculates something
save all relevant output variables again using save()
Without changing the called method, I did another run with
load the variables saved above and compare with the current input variables using isequal()
call my method again with the current input variables
load the out variables saved above and compare.
I can't believe the comparison in the last "line" detects slight differences. The calculations include single and double precision numbers, the error is in the magnitude of 1e-10 (the output is a double number).
The only possible explanation I could imagine is that either Matlab looses some precision when saving the variables (which I consider very unlikely, I use the default binary Matlab format) or that there are calculations included like a=b+c+d, which can be calculated as a=(b+c)+d or a=b+(c+d) which might lead to numerical differences.
Do you know what might be the reason for the observations described above?
Thanks a lot!
it really seems to be caused by the single/double mix in the calculations. Since I have switched to double precision only, the problem did not occur anymore. Thanks to everybody for your thoughts.
these could be rounding errors. you can find the floating point accuracy of you system like so:
>> eps('single')
ans =
1.1921e-07
On my system this reports 10^-7 which would explain discrepancies of your order
To ensure reproducible results, especially if you are using any random generating functions (either directly or indirectly), you should restore the same state at the beginning of each run:
%# save state (do this once)
defaultStream = RandStream.getDefaultStream;
savedState = defaultStream.State;
save rndStream.mat savedState
%# load state (do this at before each run)
load rndStream.mat savedState
defaultStream = RandStream.getDefaultStream();
defaultStream.State = savedState;