MATLAB: Define variable-length matrix row sub-ranges using start and stop indices

bsxfunefficiencyindexperformancespeedsubsetvectorization

% 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?

Best Answer

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.