define variable-length matrix row sub-ranges using start and stop indices

2 views (last 30 days)
% Here's an interesting problem. I've tried to make it generic so your answers
% (hopefully) will be more widely useful.
%
% Context:
% - I have a latency sensitive program.
% - I need to do some basic sub-referencing, such that I can
% - build up values in a matrix based on start and stop indices for each row.
% - I also want to be able to zero out values based on a non-index criteria.
% Assume I have:
sz = 11; % length of rows
ind_ini = [1 1 1 5 1 1]'; % starting indices
ind_end = [11 10 1 6 3 2]'; % stopping indices
vals = [1111 2222 3333 4444 5555 6666]'; % values to span index range
pts = linspace(0,1,sz); % ref values for add'l criteria
rand_max = [1 1 .3 .2 .1 .9]'; % max values for add'l criteria
% method 1
ind_logic = bsxfun(@ge,1:sz,ind_ini) & ...
bsxfun(@le,1:sz,ind_end) & ...
bsxfun(@le,pts,rand_max);
m = bsxfun(@times,ind_logic,vals); % matrix containing value spans
% method 2
n = zeros(length(vals),sz); % matrix containing value spans
for i = 1:length(vals)
n(i,ind_ini(i):ind_end(i)) = vals(i);
n(i,pts > rand_max(i)) = 0;
end
ind_logic = n > 0;
all(all(m == n))
m
% m =
%
% Columns 1 through 6
%
% 1111 1111 1111 1111 1111 1111
% 2222 2222 2222 2222 2222 2222
% 3333 0 0 0 0 0
% 0 0 0 0 0 0
% 5555 5555 0 0 0 0
% 6666 6666 0 0 0 0
%
% Columns 7 through 11
%
% 1111 1111 1111 1111 1111
% 2222 2222 2222 2222 0
% 0 0 0 0 0
% 0 0 0 0 0
% 0 0 0 0 0
% 0 0 0 0 0
% Both of these methods provide the desired output, but they seem
% computationally inefficient. The loop is inefficient for obvious reasons, and
% the bsxfun approach seems like a lot of logical map generation for something
% as "simple" as variable sub-ranges.
% What I would prefer is to have some non-iterative in-line method for
% referencing the sub-ranges of the rows in order to set them to the respective
% values. Something like:
m(ind_ini:ind_end) = vals
% where ind_ini and ind_end are the same vectors of indices. Since the lengths
% of these index-ranges are not consistent, "cells" came to mind. Something
% like:
subs = cellfun(@(x,y) x:y,num2cell(ind_ini),num2cell(ind_end),...
'UniformOutput',0)
% subs =
%
% [1x11 double]
% [1x10 double]
% [ 1]
% [1x2 double]
% [1x3 double]
% [1x2 double]
% but then I have the same problem when I try to refernce "m(subs) = vals"
% DOES ANYONE HAVE ANY CLEVER IDEAS?

Accepted Answer

Andrei Bobrov
Andrei Bobrov on 16 Jun 2011
Z = bsxfun(@times,vals,bsxfun(@le,pts,rand_max ));
mcell= arrayfun(@(j1)Z(j1,ind_ini(j1):ind_end(j1)),(1:length(ind_ini))','un',0);
EDIT
v = 1:sz;
m = cell2mat(arrayfun(@(i1)(vals(i1)*(+(ind_ini(i1)<=v&ind_end(i1)>=v&pts<=rand_max(i1))))',1:length(ind_ini),'un',0))'
about speed ... try the following:
v=1:sz;for i1 = length(ind_ini):-1:1, m(i1,:) = vals(i1)*(+(ind_ini(i1)<=v&ind_end(i1)>=v&pts<=rand_max(i1))); end;
my research
tic;v=1:sz;ind_logic = bsxfun(@ge,v,ind_ini) &bsxfun(@le,v,ind_end) & bsxfun(@le,pts,rand_max);m = bsxfun(@times,ind_logic,vals);toc
Elapsed time is 0.000668 seconds.
>> tic;v = 1:sz;m = cell2mat(arrayfun(@(i1)(vals(i1)*(+(ind_ini(i1)<=v&ind_end(i1)>=v&pts<=rand_max(i1))))',1:length(ind_ini),'un',0))';toc
Elapsed time is 0.001297 seconds.
>> tic,v=1:sz;for i1 = length(ind_ini):-1:1, m(i1,:) = vals(i1)*(+(ind_ini(i1)<=v&ind_end(i1)>=v&pts<=rand_max(i1))); end; toc
Elapsed time is 0.000113 seconds.
  4 Comments
Andrei Bobrov
Andrei Bobrov on 19 Jun 2011
about speed
<http://www.mathworks.com/matlabcentral/answers/7039-how-to-multiply-a-vector-with-each-column-of-a-matrix-most-efficiently>
Hannes Greim
Hannes Greim on 19 Jun 2011
Thanks. That works in the example I provided. It's certainly faster when the dimensions of the input arrays are small enough. It does not scale as well as bsxfun with larger arrays. Thanks for your input.

Sign in to comment.

More Answers (1)

Hannes Greim
Hannes Greim on 19 Jun 2011
Andrei's answer is faster when the input arrays are small. The example below shows that the bsxfun approach has a larger overhead, but scales much better for larger arrays.
edit func_1.m
% ------------------------------------------------------------------------------
function [m] = func_1(ind_ini,ind_end,vals,rand_max)
sz = 11; % length of rows
pts = linspace(0,1,sz); % ref values for add'l criteria
v = 1:sz;
ind_logic = bsxfun(@ge,v,ind_ini) &...
bsxfun(@le,v,ind_end) & ...
bsxfun(@le,pts,rand_max);
m = bsxfun(@times,ind_logic,vals);
end
% ------------------------------------------------------------------------------
% ------------------------------------------------------------------------------
edit func_2.m
% ------------------------------------------------------------------------------
function [m] = func_2(ind_ini,ind_end,vals,rand_max)
sz = 11; % length of rows
pts = linspace(0,1,sz); % ref values for add'l criteria
v = 1:sz;
for i1 = length(ind_ini):-1:1
m(i1,:) = vals(i1)*(+(ind_ini(i1)<=v&ind_end(i1)>=v&pts<=rand_max(i1)));
end
end
% ------------------------------------------------------------------------------
% ------------------------------------------------------------------------------
ind_ini = [1 1 1 5 1 1]'; % starting indices
ind_end = [11 10 1 6 3 2]'; % stopping indices
vals = [1111 2222 3333 4444 5555 6666]'; % values to span index range
rand_max = [1 1 .3 .2 .1 .9]'; % max values for add'l criteria
tic;for i=1:1e5,m=func_1(ind_ini,ind_end,vals,rand_max);end;toc
% Elapsed time is 8.417756 seconds.
tic;for i=1:1e5,m=func_2(ind_ini,ind_end,vals,rand_max);end;toc
% Elapsed time is 6.002761 seconds.
mult = 3;
ind_ini = repmat(ind_ini,mult,1);
ind_end = repmat(ind_end,mult,1);
vals = repmat(vals,mult,1);
rand_max = repmat(rand_max,mult,1);
tic;for i=1:1e5,m=func_1(ind_ini,ind_end,vals,rand_max);end;toc
% Elapsed time is 8.182190 seconds.
tic;for i=1:1e5,m=func_2(ind_ini,ind_end,vals,rand_max);end;toc
% Elapsed time is 9.983013 seconds.
ind_ini = repmat(ind_ini,mult,1);
ind_end = repmat(ind_end,mult,1);
vals = repmat(vals,mult,1);
rand_max = repmat(rand_max,mult,1);
tic;for i=1:1e5,m=func_1(ind_ini,ind_end,vals,rand_max);end;toc
% Elapsed time is 8.710443 seconds.
tic;for i=1:1e5,m=func_2(ind_ini,ind_end,vals,rand_max);end;toc
% Elapsed time is 23.056634 seconds.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!