Asymmetric intervals built-in vectorisation

1 view (last 30 days)
Does Matlab have a built-in methodology to vectorise the following?
a = [3,4,3,6,4,2];
b = zeros(1, sum(a));
idxEnd = cumsum(a);
idxStart = [1 idxEnd(1:end-1) + 1];
for j = 1 : length(a)
b(idxStart(j):idxEnd(j)) = 1:a(j);
end
This codes collect asymmetric linear spaces in one variable.
With an abuse of notation, my objective is to:
b = ones(size(a)) : a
But of course this does not work.
I often have this kind of problem and I try to avoid loops as much as possibile.
It's just weird that a highly vectorised language like Matlab cannot perform this, so I guess I'm missing something.
I thought about cellfun but I think it would use a for loop aswell.

Accepted Answer

John D'Errico
John D'Errico on 20 Apr 2023
Edited: John D'Errico on 20 Apr 2023
You can decide that some syntax is what you want to have work, but there are limits. And I would no be surprised if someone else might decide the syntax you see in your minds eye does something completely different. It looks like you want a vector that looks like the teeth of a saw, increasing linearly, then dropping down to one again. And of course, you want it to work in a fully vectorized way.
First, the obvious answer is to just create a cell array, then collapse those cells into one vector. That would be trivial to write. Or, you could use a loop, which I would expect to be fairly fast. Loops are not terrible things in MATLAB. And if this is something that you want to do often in MATLAB, then just write your own function, extending MATLAB to be what you want it to be. That is the beauty of a language like this. You can make it be YOUR own language easily enough.
Finally, you could write a vectorized code. Again, not too hard. Just use cumsum. There are no error checks in the codes below. And no good documentation. You can add that as you please. First, do each of these schemes work?
a = [2 3 7 5];
saw1(a)
ans = 1×17
1 2 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5
saw2(a)
ans = 1×17
1 2 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5
saw3(a)
ans = 1×17
1 2 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5
And as we can see, they all work. Are they all fast? Probably reasonably so.
a = randi(500,[1,1000]);
timeit(@() saw1(a))
ans = 0.0013
timeit(@() saw2(a))
ans = 0.0026
timeit(@() saw3(a))
ans = 4.0974e-04
So we see each is not really that bad. The loop was twice as fast as using arrayfun, then cellfun. But what you should understand is that arrayfun and cellfun are just slick ways of implementing implicit internal loops. They often do not speed things up by a lot. So I'm not amazed that saw2 is the slowest. saw3 is faster than the loop, but not hugely so. A little better than twice as fast.
function V = saw1(a)
% sawtooth vector, looped
V = zeros(1,sum(a));
m = 0;
for i = 1:numel(a)
V(m+1:m+a(i)) = 1:a(i);
m = m + a(i);
end
end
function V = saw2(a)
% sawtooth vector, cell
C = arrayfun(@(x) 1:x,a,'UniformOutput',false);
V = horzcat(C{:});
end
function V = saw3(a)
% sawtooth vector, cumsum
V = ones(1,sum(a));
c = cumsum(a(1:end-1));
V(1+c) = -a(1:end-1)+1;
V = cumsum(V);
end
If you want, then name your preferred function whatever you like, and save it. Now you have code in MATLAB that does exactly what you want. I'd add some documentation, and some error checks on a. For example, you might decide to make sure that a is always positive, and always composed of integers.
To be honest though, I have never had the need to build such a vector, and if I did, I'd probably just use a loop unless this was a serious bottleneck in my code. All of these were quite fast, even for a rather large problem. My rule is to never write difficult to read, specialized code, wasting programmer time to make your code run a tiny bit faster on a one-off problem. Instead, spend that programming time to solve a more difficult problem that needs work.
  2 Comments
John D'Errico
John D'Errico on 20 Apr 2023
Yeah, the third one is cute. It was what I originally visualized as the solution, and what I expected to be the fastest. because it is mainly just cumsum, but with the elements artfully placed before the cumsum. So it does the least amount of real work.

Sign in to comment.

More Answers (0)

Categories

Find more on Loops and Conditional Statements 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!