Changing the type of the built-in function output variable
Show older comments
Is it possible to force Matlab to change the type of output variable returned from the built-in function (which I cant control) ?
For example if I have x=randi(255,1e7,1,'uint8'); and want to do [ux,~,id]=unique(x); the variable id will be of double type and occupy unnecessarily huge space before I trim it down with id=uint8(id); since I know max(id)<256. I would like to force id to uint8 type such that it does not create a spike in memory requirement during calling Matlab's unique, which might go over RAM and stall execution.
Any ideas if this is possible?
9 Comments
Bjorn Gustavsson
on 4 Feb 2021
That looks like a request to Mathworks. However, since uints span 256 unique values, id will have to span 1-256, while uint8 doesn't reach 256 - this seems like problem due to 1-indexing arrays I guess...
Walter Roberson
on 4 Feb 2021
id will equal x in that code, with probability very very high
dymitr ruta
on 4 Feb 2021
Walter Roberson
on 4 Feb 2021
id(:) as output calculates the entire output in double and then assigns it to the variable. No memory is saved.
Walter Roberson
on 4 Feb 2021
Seriously, for a value not to appear at all even once in 1e7 random trials, the probability would have to be down in the range of 1e-12.
dymitr ruta
on 4 Feb 2021
As Bjorn has mentioned already, randi(255, 'uint8') produces values from 1 to 255. A real test with uint8 values must consider 256 elements including the 0. Then the id cannot be an UINT8, because it cannot carry the value 256.
I've fixed this in my answer: id is an UINT16. Still 20 times faster with a lookup table than with Matlab's UNIQUE.
Walter Roberson
on 4 Feb 2021
Would there happen to be a prefix size by which you could be sure that you would have encountered all of the values that will be seen in the table? For example if there were four different values, would it always be the case that all four would be encounted by x(1:1000) ? Or is it likely that some of the values will not occur until late in x ?
Paul
on 5 Feb 2021
After converting to a categorical it looks like the end result does not use doubles for the encoding. Does it use doubles under the hood in an interim step?
> whos
Name Size Bytes Class Attributes
cx 10000000x1 20029990 categorical
id1 10000000x1 80000000 double
id2 10000000x1 20000000 uint16
pool 1x256 512 uint16
ux1 256x1 256 uint8
ux2 256x1 256 uint8
x 10000000x1 10000000 uint8
id1, id2, pool, ux1, ux2 from running the first two parts of Jan's answer.
Accepted Answer
More Answers (1)
And another version which is 5% faster than my other answer, if not all 256 possible values are found. If all values appear in the input, it can be 10 times faster:
function [ux, idx] = UniqueUINT8(x)
% INPUT: x: UINT8 vector
% OUTPUT: ux: sorted unique values of x
% idx: indices such that ux(idx)==x
% The values are used as indices in a lookup table. Shift values by 1 to let 0
% become a valid index. Then 255 becomes 256, such that UINT16 is required:
xx = (uint16(x) + uint16(1));
% Create a table as logical vector:
T = false(1, 256);
% Fill the table by values of xx:
% Short version: T(xx) = true;
% It is faster to do this in chunks. This can be stopped if tab is filled with
% all possible 256 elements already:
chunk = 1e5; % Chuck length
len = numel(xx); % Number of elements
ini = 1; % Initial index of chunk
fin = min(chunk, len); % final index of chunk
while ini < fin && ~all(T) % Loop in chunks
T(xx(ini:fin)) = true; % Fill table
ini = fin + 1; % Advance chunk limits:
fin = min(ini + chunk, len);
end
ux = (uint8(0):uint8(255)).';
if all(T) % Faster version for complete table:
idx = xx; % Shifted values are the indices already
else
ux = ux(T).'; % UINT8(find(T) - 1), the original unique values
if nargout > 1
LUT = zeros(1, 256, 'uint16');
LUT(T) = uint16(1):uint16(numel(ux)); % Look up table of indices
idx = LUT(xx).';
end
end
end
Categories
Find more on Tables in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!