2
votes

I am currently writing a function that converts a cell array into sparse block matrix.

I did achieve my purpose and now I am trying to optimize the code, but I just cannot seem to find a way to speed up the vectorization of matrices within the cell.

Currently, I have set the input as a column cell vector like the following:

Input = cell(Blocks,1);

Each cell inside the input has variously sized matrices.

To vectorize the matrices inside the cell, I am currently using this code:

V = cellfun(@(x) x(:), Input, 'un', 0);

But my profiler keeps on telling me that this part of my code takes up a lot of time.

I did try to change this into a for loop:

Blks = size(Input,1);

V = cell(Blks,1);

for i = 1:Blks
    V{i} = Input{i}(:);
end

However, this only makes my code run slower than my previous code.

Is there another alternative way to speed up the vectorization process of the matrices within the cell?

Thank you very much in advance!


I wanted to add another information.

After I calculate V, I concatenate all the cells and turn them into a single vector Val by doing so:

Val = cat(1,V{:});

At first I tried using cell2mat instead of cat, but it turns out that cat is much faster.

If there is a way to calculate Val without going through calculating V, it would be much better :)

Thanks again!

1

1 Answers

0
votes

this might not be the most efficient way, but I get a 50% improvement on run time:

% Time the two versions of the algorythm
t1 = timeit(@test1)
t2 = timeit(@test2)
disp([num2str((t1 - t2) / t1 * 100) ' % improvement'])

% Prepare the same input for the two functions, 5 cells
% with random sized matrices
Input = cell(1,5);
for k = 1 : 5
    Input(k) = {randn(abs(round(randn(1,2).*10)))};
end

% Check if the results are the same
disp(all(test1(Input) == test2(Input)))



function Val = test1(varargin)
    if isempty(varargin)
    % Prepare three cells for testing
        Input(1) = {randn(5,4)};
        Input(2) = {randn(8,3)};
        Input(3) = {randn(2,4)};
    else
        Input = varargin{1};
    end

    % Your current method
    V = cellfun(@(x) x(:), Input, 'un', 0);
    Val = cat(1,V{:});
end


function Val = test2(varargin)
    if isempty(varargin)
    % Prepare three cells for testing
        Input(1) = {randn(5,4)};
        Input(2) = {randn(8,3)};
        Input(3) = {randn(2,4)};
    else
        Input = varargin{1};
    end

    % Store size of all matrices in the cells. I am adding 
    % a 0 at the beginning of the array for the indexing of
    % the following cycle
    s = [0 , cellfun(@numel, Input)];

    % Pre-allocate variable
    Val = zeros(sum(s) , 1);
    % Fill variable
    for k = 1:numel(Input)
        Val(sum(s(1:k))+1 : sum(s(1:k+1)) ) = Input{k}(:);
    end
end

I get:

t1 =

1.2515e-04

t2 =

6.0825e-05

51.3965 % improvement