Pre-Allocating Single Cell's Memory - matlab

I am writing a code and would like to know how to pre-allocate the memory for a single cell. I understand that one can easily pre-allocate an array of cells, but this isn't what I'm looking for.
My code follows the following logic:
for i = 1:numel(k)
R{i} = % Some 4x4 matrix That changes each iteration
end
R = blkdiag(R{:});
The goal here is to build a comma-separated list of an arbitrary amount of matrices, say:
R = {A,B,C,D,E,...}
Such that blkdiag will return the following:
R = [A 0 0...
0 B 0...
0 0 C...
... ]
The code I have right now works fine, I'd just like to know how to pre-allocate memory for this case such that it runs faster if I had an awful lot of matrices.

Putting a matrix into a cell array doesn't cause the cell array to be resized, if your cell array was preallocated. R = cell(numel(k),1) will preallocate the cell array. Each element of this array is a reference to an array (or arbitrary type, could be a numeric array, another cell array, a struct array, an array of custom objects, doesn't matter).
When the cell array is first created, each cell contains an empty matrix, []. Replacing this matrix just changes the reference stored in the cell array to point to a different array. R{3} = x doesn't reallocate memory, it only changes the reference in R{3} to now point to whatever matrix was stored in the variable x.
On the other hand, if you want to add values to the array stored in R{3}, you should preallocate that array:
R{3} = zeros(5,1); % preallocate the array pointed to by R{3}
for ii=1:5
R{3}(ii) = ii;
end

Related

Manipulate values in Matlab cell array

Suppose I have a 3x1 cell array called subj that has the following elements:
cell 1: 300x20 double
cell 2: 300x15 double
cell 3: 300X18 double
I want to remove the last quarter rows from every element in each cell as follows:
subj{1}(length(subj{1})*0.25+1:end,:) = []
subj{2}(length(subj{2})*0.25+1:end,:) = []
subj{3}(length(subj{3})*0.25+1:end,:) = []
However I want to be do this in one line and can't figure out a way to do this in Matlab. I messed around with converting the cell array to a matrix, but since there different numbers of columns, it makes it slightly more complicated. Is there a vectorized way to do this in one line? I will be applying machine learning algorithms to each element of subj and it would be great to have this be vectorized for later parts of my code.
Better not assigning empty arrays to a matrix (actually that doesn't work) but reassign the matrix itself:
% loop over the cell array
for i = 1:length(subj)
% determine the index/number of rows. Don't forget to round as MATLAB requires integers for slicing!
idx = round( length(subj{i})*0.25 );
% get the new matrix
NewMat = subj{i}(1:idx,:);
% assign new matrix to the old address, i.e. the content of the cell
subj{i} = NewMat;
end
MATLAB allocates contiguous memory for matrices, so cropping it shouldn't cause much overhead. In particular not as it uses "lazy copying" and; therefore, only copies the matrix when you change any of its values.

Extracting field from cell array of structure in matlab

I have a cell array (let's say size 10) where each cell is a structure with the same fields. Let's say they all have a field name x.
Is there a way to retreive in a vector the value of the field x for all the structure in the cell array? I would expect the function to return a vector of size 10 with in position 1, the value of the field x of the structure in cell 1 etc etc...
EDIT 1:
The structure in the cell array have 1 field which is the same for all but some others which are different.
First convert your cell array of structures, c, (with identical field names in the same order) to a structure array:
c = cell2mat(c)
Then, depending on the data types and sizes of the elements of the field, you may be able to use
[c.x]
to extract your vector of field x values in the "standard" way.
It is also possible that you can skip the conversion step and use cellfun(#(e)e.x, c) to do the extraction in one go.
The below code creates a cell array of structures, and extracts field 'x' of each structure to a vector v.
%create a cell array of structures
s1.a = 'hello';
s1.x = 1;
s2.a = 'world';
s2.x = 2;
c{1} = s1;
c{2} = s2;
v = zeros(1,2);
%extract to vector
for idx=1:size(c,2)
v(1,idx) = c{idx}.x;
end
Let's say you have
c = {s1, s2, s3, ...., sn};
where common field is 'field_1', then you have two options
Use cell2mat.
cc = cell2mat(c); % which converts your cell array of structs into an array of structs
value = [cc.field_1]; % if values are number
or
value = {cc.field_1}; % if values are characters, for example
Another option is to use cellfun.
If the field values are characters, you should set "UniformOutput" to "false"
value = cellfun(#(x) x.field_1, c, 'UniformOutput', false)
The first option is better. Also, try to avoid using cell/cellfun/arrayfun whenever you can, vectors are way faster and even a plain for loop is more effecient

Avoid looping in matlab when creating cells containing cell arrays

I'm trying to create a map that has two-element cell arrays as values. Map expects that keys and values have the same number of elements. This code packs those cell arrays into cells in a loop, but I'm suspecting that it can be simplified somehow. Example code:
cells1={'foo1';'foo2';'foo3'};
cells2={'bar1';'bar2';'bar3'};
cells3={'baz1';'baz2';'baz3'};
values=cell(size(cells1));
for ii=1:size(cells1,1)
values{ii}={{cells2{ii},cells3{ii}}};
end
keys=cells1;
containers.Map(keys,values);
you can use vector concatenation and num2cell with 2nd dimension argument (twice if you want to obtain identical result):
% your code
cells1={'foo1';'foo2';'foo3'};
cells2={'bar1';'bar2';'bar3'};
cells3={'baz1';'baz2';'baz3'};
values=cell(size(cells1));
for ii=1:size(cells1,1)
values{ii}={{cells2{ii},cells3{ii}}};
end
% simplified
c = num2cell(num2cell([cells2,cells3],2),2);
% you can also do c = num2cell([cells2,cells3],2); which isn't identical but may be suficcient
isequal(c,values) % yes

Matlab -- Copy Structure Array without For Loop

I have a fairly simple question in Matlab. I want to copy n items of structure array (sumRT.P) to a matrix (m). In C, I would just use a for loop, like this:
for i = 1:n
m(i) = sumRT(i).P;
end
But I bet there's a simpler way to copy an array in Matlab (that's the whole point of language right?). I tried this:
m = sumRT(1:n).P;
But this just copies the first item in sumRT.P to m, resulting in a 1 X 1 matrix. Note, if I type, sumRT(2).P for example, I can see the second item. Same for any number up to n. Why is this wrong and how do I fix it?
It depends on the data types in your structure array. If they are types of variables, or if they are variables of the same size in arrays of different dimensions, then you can't put them into an array, but you can make them into a cell:
m={sumRT(1:n).P}
and cells are pretty simple to deal with, so this oughtn't be a big problem.
If they are all scalar numerical values, you can create a matrix:
m=cell2mat({sumRT(1:n).P})
Try the following:
m = squeeze(cell2mat(struct2cell(sumRT(1:n))));
This converts the struct array to a cell array, and then to a (numeric) array, and then squeezes it by remoiving singleton dimensions.
Example:
>> sumRT(1).P = 10; sumRT(2).P = 20; sumRT(3).P = 30;
>> n = 2; %// copy first two elements only
>> m = squeeze(cell2mat(struct2cell(sumRT(1:n))))
m =
10
20

MATLAB: index a cell array with cell array of arrays and return a cell array

Say I have a cell array of (n X 1) vectors, A, and a cell array of vectors containing indices into A, called B. I wish to extract a cell array, C, such that C{i} = [A{B{i}}].
In other words, I have a cell array of arrays of indices, and I want to pull out the matrices corresponding to the concatenations of the vectors in A indexed by each of those arrays of indices.
for i = 1:length(B)
%# B{i} is an array of indices, C{i} is a matrix
C{i} = [ A{ B{i} } ];
end
The loop is equivalent to:
C = cellfun(#(x)[A{x}],B,'UniformOutput',false); %# implicit for loop w/ closure
Can I do that using an indexing expression alone? Or at least without the loop?
I think deal() might have to be involved but can't figure it out.
Here are two alternative solutions:
Collect all the indices of B together with the function cell2mat, index the contents of A to make one large matrix, then divide that matrix up using the function mat2cell and the sizes of the index arrays in B:
N = size(A{1}); % Size of an array in A
M = cellfun('prodofsize', B); % Array of sizes of elements in B
C = mat2cell([A{cell2mat(B)}], N, M);
Here's a more compact version of your cellfun-based solution:
C = cellfun(#(x) {[A{x}]}, B);
Ultimately, I would decide what solution to use based on speed and readability, which may actually turn out to be your for-loop-based solution.
Try the following expression:
C = A(cell2mat(B))
You may have a look at Loren's blog post about Cell Arrays and Their Contents