2

Finding if all elements of a matrix are finite, fast!

 2 years ago
source link: https://blogs.mathworks.com/matlab/2022/05/12/finding-if-all-elements-of-a-matrix-are-finite-fast/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Finding if all elements of a matrix are finite, fast! » The MATLAB Blog

Today, I'm going to focus on three new functions that were added to the MATLAB programming language in R2022a: allfinite, anynan and anymissing. These functions are more concise, and usually faster, than alternative methods
Are all matrix elements finite? Doing it the old way.
How do you check if all the elements of a matrix are finite or not? Here's a matrix where the answer is 'No' by design.
a=rand(3);a(2,2)=inf
a = 3×3
0.6945 0.8625 0.0988 0.0722 Inf 0.7485 0.8283 0.2797 0.5190
A common pattern for testing if every element in a matrix is finite is to first apply the isfinite function which returns a logical array:
checkFinite = isfinite(a)
checkFinite = 3×3 logical array
1 1 1 1 0 1 1 1 1
and then pass this to the all function which checks if all the entries of each column are true or not
checkAllRowsFinite = all(checkFinite)
checkAllRowsFinite = 1×3 logical array
we apply the all function one more time to get the result we want
checkAllFinite = all(checkAllRowsFinite)
checkAllFinite = logical
No! All the entries of our original matrix are not finite! Usually, all of the above is put into one line:
checkAllFinite = all(all(isfinite(a)))
checkAllFinite = logical
This was a common pattern for many years and things could get out of hand when dealing with multiple dimensional arrays. For example to check if every element of
a=rand(3,3,3,3);
is finite, we'd need to do
checkAllFinite = all(all(all(all(isfinite(a)))))
checkAllFinite = logical
That's a lot of all! Some people use the concise but arguably cryptic
checkAllFinite = all(isfinite(a(:)))
checkAllFinite = logical
So, in R2018b, we introduced a new way of doing this that's nicer to read
checkAllFinite = all(isfinite(a),'all')
checkAllFinite = logical
New in R2022a: allfinite - Finding if all is finite, fast
We see these patterns a lot in both our code and user's code. So much so that in R2022a, we've developed another function to make it even easier to perform this common operation: allfinite
a = rand(3);a(2,2)=inf;
CheckAllFinite = allfinite(a)
CheckAllFinite = logical
We didn't do this just to save on typing though. We did it because it's faster! You see the biggest difference with a large number of small matrices. Let's look at 10 million 3 x 3 matrices.
a3 = rand(3);
for i =1:1e7
tf = all(isfinite(a3), 'all');
oldMethodTime = toc
oldMethodTime = 0.7560
for i =1:1e7
tf = allfinite(a3);
newMethodTime=toc
newMethodTime = 0.0847
fprintf("allfinite(a3) is %.2f times faster than all(isfinite(a3), 'all') for " + ...
"10 million small matrices\n",oldMethodTime/newMethodTime)
allfinite(a3) is 8.93 times faster than all(isfinite(a3), 'all') for 10 million small matrices
That can add up to quite a difference in functions that are called a lot. The benefit is reduced for larger matrices but it's still useful
a2000 = rand(2000);
for i =1:1e3
tf = all(isfinite(a2000), 'all');
oldMethodTime = toc
oldMethodTime = 2.9144
for i =1:1e3
tf = allfinite(a2000);
newMethodTime=toc
newMethodTime = 0.8977
fprintf("allfinite(a2000) is %.2f times faster than all(isfinite(a2000), 'all') for " + ...
"1000 large matrices\n",oldMethodTime/newMethodTime)
allfinite(a2000) is 3.25 times faster than all(isfinite(a2000), 'all') for 1000 large matrices
Are there any NaNs or is anything missing?
Along with allfinite, the MATLAB math team identified two other patterns that could be optimised in a similar way and came up with the functions anynan and anymissing. When working with arrays, there will almost always be a speedup although you may have to run it many times to see it.
B = 0./[-2 -1 0 1 2]
B = 1×5
0 0 NaN 0 0
repeats = 1e6;
for i =1:repeats
tf = any(isnan(B), 'all');
oldMethodTime = toc
oldMethodTime = 0.0887
for i =1:repeats
tf = anynan(B);
newMethodTime=toc
newMethodTime = 0.0126
fprintf("anynan(B) is %.2f times faster than any(isnan(B), 'all') for " + ...
"%d small vectors\n",oldMethodTime/newMethodTime,repeats)
anynan(B) is 7.03 times faster than any(isnan(B), 'all') for 1000000 small vectors
Is anynan faster for all datatypes?
For some data types, you might not see a speedup but it will be, at worst, as good as existing methods. Consider this example for checking for missing values in a table
singleVar = single([1;3;5;7;9;11;13]);
cellstrVar = {'one';'three';'';'seven';'nine';'eleven';'thirteen'};
categoryVar = categorical({'red';'yellow';'blue';'violet';'';'ultraviolet';'orange'});
dateVar = [datetime(2015,1:7,15)]';
stringVar = ["a";"b";"c";"d";"e";"f";"g"];
mytable = table(singleVar,cellstrVar,categoryVar,dateVar,stringVar)
mytable = 7×5 table
singleVarcellstrVarcategoryVardateVarstringVar
11'one'red15-Jan-2015"a"
23'three'yellow15-Feb-2015"b"
35''blue15-Mar-2015"c"
47'seven'violet15-Apr-2015"d"
59'nine'<undefined>15-May-2015"e"
611'eleven'ultraviolet15-Jun-2015"f"
713'thirteen'orange15-Jul-2015"g"
Previously, you might have checked this as follows
TF = any(ismissing(mytable),'all')
TF = logical
Now, we can do
TF = anymissing(mytable)
TF = logical
The times are about the same so we can safely use these new functions all the time. Let's run it 5000 times to see
repeats = 5e3;
for i =1:repeats
tf = any(ismissing(mytable),'all');
oldMethodTime = toc
oldMethodTime = 0.4411
for i =1:repeats
tf = anymissing(mytable);
newMethodTime=toc
newMethodTime = 0.3786

Updating MathWorks code to use these new functions

We've started using these new functions straight away in many MATLAB functions. They're used in argument validation in functions like expm, logm and median among others. Take a look for yourself by looking at the source code with, for example
edit sqrtm

Over to you

In a release as big as R2022a that has many shiny features, simple functions such as these can often get overlooked. They are, however, useful new ways of performing very common operations. Teams at MathWorks are already starting to use them thoughout the codebase to make improvements here and there and I am sure I'll get the chance to usefully use them in user's code soon enough.
Do you think they'll be useful in your workflow? Are there any similar functions you wish MATLAB had?

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK