Thursday, 21 January 2016

Matlab minimum for variables of different dimensions with the min() function

When using the Matlab function min() to find the minimum value of a variable, I wanted to use it for data that was in more than just 1 dimension. I received the following error message when running my code:

Error using min
Matrix dimensions must agree.

The problem here is that I was trying to find the minimum of several variables together, and the variables each had different dimensions.

Furthermore, the function acts somewhat differently to what I would expect. Consider the following initialisation:

>> data=[[1:10];[1:10]]
data =
     1     2     3     4     5     6     7     8     9    10
     1     2     3     4     5     6     7     8     9    10

Here the data fills a 2 x 10 matrix. I would expect the min() function to return one value for the entire matrix. Instead, the min() function returns the minimum for each column.

>>  min(data)
ans =
     1     2     3     4     5     6     7     8     9    10

One solution is to use multiple min() calls as follows:

>> min(min(data))
ans =
     1

But this isn't a great solution, as you might require this multiple times. So the solution is to use (:) to reference the elements of the matrix. This references all of the elements consecutively, and results in a 1 dimensional matrix containing all elements.

data(:)
ans =
     1
     1
     2
     2
     3
     3
     4
     4
     5
     5
     6
     6
     7
     7
     8
     8
     9
     9
    10
    10

As the data is now one dimensional, the min() function will work on the data in this format, as follows:

>> min(data(:))
ans =
     1

This is how I would have expected the min() function to behave by default, but at least this works for one variable. However if I now want to use it to find the minimum from multiple variables, again the behaviour starts to cause a problem. I will create two 2x10 matrices for testing as follows:

>>  a=[[1:10];[1:10]]
a =
     1     2     3     4     5     6     7     8     9    10
     1     2     3     4     5     6     7     8     9    10
>>  b=[[11:20];[11:20]]
b =
    11    12    13    14    15    16    17    18    19    20
    11    12    13    14    15    16    17    18    19    20

If trying to find the minimum by passing both variables to the min() function, this again doesn't work entirely as expected.

>>  min(a(:), b(:))
ans =
     1
     1
     2
     2
     3
     3
     4
     4
     5
     5
     6
     6
     7
     7
     8
     8
     9
     9
    10
    10

The reason for this is that Matlab sees the two variables as two columns of data that have been joined together, and then passed to the function. Matlab processes the data as follows:

>> [a(:),b(:)]
ans =
     1    11
     1    11
     2    12
     2    12
     3    13
     3    13
     4    14
     4    14
     5    15
     5    15
     6    16
     6    16
     7    17
     7    17
     8    18
     8    18
     9    19
     9    19
    10    20
    10    20

So we can see that the min() function actually finds which dimension is longest, and finds the minimum value in the shorter dimension. If we transpose the matrix first using the apostrophe, and then use the min function, the function is still operating on the longest dimension.

>> [a(:),b(:)]'
ans =
  Columns 1 through 18
     1     1     2     2     3     3     4     4     5     5     6     6     7     7     8     8     9     9
    11    11    12    12    13    13    14    14    15    15    16    16    17    17    18    18    19    19
  Columns 19 through 20
    10    10
    20    20
>> min([a(:),b(:)]')
ans =
  Columns 1 through 18
     1     1     2     2     3     3     4     4     5     5     6     6     7     7     8     8     9     9
  Columns 19 through 20
    10    10

There are a couple of obvious workarounds for this problem. The first would be to use multiple min() function calls, as follows:

>> min(min(a(:),min(b(:))))
ans =
     1

This isn't a particularly nice line of code, with three min() function calls. An alternative that I find better  can be created by appending the data before calling the min() function, and is as follows:

>> min([a(:); b(:)])
ans =
     1

Care must be taken to use the semicolon in between the matricies to minimum value, if using a column this will create two columns of data, and the min() function then returns two values as follows:

>>  min([a(:), b(:)])
ans =
     1    11

I'm not sure why in this case the min() function is now only returning two values, and not working in the longest dimension like it was previously.

Alternatively if using the comma to separate variables, the variables can be trtansposed first, in which case the function works, but this is more work for the same result and so isn't recommended.

>> min([a(:)', b(:)'])
ans =
     1

Summary

The behaviour of the min() function is to find the minimum value in a given matrix, not the absolute minimum in the data passed to the function. To get the function to behave in this manner requires some changing of the data format before the data is passed to the function. I believe the cleanest format is the following:

>> min(min(a(:),min(b(:))))
ans =
     1


No comments:

Post a Comment