DEV Community

monty5811
monty5811

Posted on • Originally published at deanmontgomery.com on

Matlab: getting rid of nested loops

Ever seen matlab code that looks like this? Maybe you are doing a grid search?

for x = 1:10
  for y = 1:5
    for z = 1:100
      for t = 1:2
        do_something(x, y, z, t)
      end
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

This is pretty nasty, can we make this look better?

How about something like this?

params.X = 1:10;
params.Y = [2, 4, 8];

vectorized_parameters = build_vecd_params(params);
N = size(vectorised_parameters, 1);
for x = 1:N
    candidate = get_row_as_struct(params, vectorised_parameters, x);
    do_something(candidate);
end

Enter fullscreen mode Exit fullscreen mode

This looks much nicer, we don’t have nested loops and adding a new parameter to loop over is much cleaner.

We can even randomise the looping order pretty easily:

N = size(vectorised_parameters, 1);
iteration_order = randperm(N);
for x = 1:N
    idx = iteration_order(x);
    candidate = get_row_as_struct(params, vectorised_parameters, idx);
    do_something(candidate);
end

Enter fullscreen mode Exit fullscreen mode

How it works

We need to create the two functions:

  • build_vecd_params to create a matrix where each row is a single permutation of all variables we want to loop over
  • get_row_as_struct: to extract a row of the matrix and give us back a struct we can use to easily access each looping variable
function [vectorised_parameters] = build_vecd_params(params)
% params is a struct like
% params.X = 1:10;
% params.Y = [2, 4, 8];

all_ranges = struct2cell(params);
N = numel(all_ranges);
[grid{1:N}] = ndgrid(all_ranges{:});
vectorised_parameters = reshape(cat(N + 1, grid{:}), [], N);
end

function [candidate] = get_row_as_struct(params, vectorised_parameters, idx)
% return a `candidate` permutation of our loop variables
row = vectorised_parameters(idx, :);
fns = fieldnames(params)';
assert(numel(row) == numel(fns)); % sanity check
c = 1;
for fn_ = fns
    fn = char(fn_);
    candidate.(fn) = row(c);
    c = c + 1;
end
assert(c - 1 == numel(row)) % sanity check
end

Enter fullscreen mode Exit fullscreen mode

How to use it

Just copy the two functions above into your matlab file and you’re off to the races.

Top comments (0)