Matlab: getting rid of nested loops
02 Jun 2020
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
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
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
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 overget_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
How to use it
Just copy the two functions above into your matlab file and you’re off to the races.