Improving efficiency of using tables

5 views (last 30 days)
Tejas
Tejas on 22 May 2021
Answered: Abhas on 19 Feb 2024
A simple working example of my code is given below.
% Initialization
num = 10; time_limit = 10000;
agent = array2table(zeros(num,4),'VariableNames',{'loc','prev_loc','loc_time','collected'});
env = randi(10,10,10); env(1,1) = 0;
agent.loc = ones(num,1);
% Collect rewards one-by-one
agent.loc_time = ones(num,1);
tic
for t = 1:time_limit
for i = 1:num
% If agent i has reached a position at time t
if agent.loc_time(i) == t
% If there is a reward at agent's location
if env(agent.loc(i)) > 0
[agent(i,:),env] = return_with_reward(agent(i,:),env);
% Otherwise
else
[agent(i,:),env] = find_reward(agent(i,:),env);
end
end
end
end
toc
function [agent,env] = find_reward(agent,env)
agent.prev_loc = agent.loc;
% Select a location to go randomly
agent.loc = randi([2,length(env(:))],1);
% Find time to get there
agent.loc_time = agent.loc_time + abs(agent.loc - agent.prev_loc);
end
function [agent,env] = return_with_reward(agent,env)
loc = agent.loc;
% Update environment
env(loc) = max(0, env(loc) - 1);
agent.collected = agent.collected + 1;
agent.prev_loc = loc;
% Return to starting position
agent.loc = 1;
% Find time to reach
agent.loc_time = agent.loc_time + abs(agent.loc - agent.prev_loc);
end
In this, the agents start at position (1,1), go to random positions till they get a reward, return with that reward to (1,1), and go again. For 10 agents and 10k time steps, this takes about 2 seconds. I'm new to table-oriented programming, so I'm wondering if there are ways I can improve the efficiency of this process.

Answers (1)

Abhas
Abhas on 19 Feb 2024
Hi Tejas,
We can optimize the code by improving the following key factors:
  1. Precomputing Random Locations: All random locations are generated before the loop, reducing runtime overhead.
  2. Vectorized Logical Indexing: Agents are processed in batches using logical indexing, which is faster than iterative loops.
  3. Batch Updating: Agents that found a reward and those that did not are updated in separate batches, leveraging MATLAB's efficient handling of array operations.
  4. Direct Assignment: The starting position for agents returning with a reward is assigned in one operation, rather than in a loop.
The optimized MATLAB code is as follows:
% Initialization
num = 10; time_limit = 10000;
agent = array2table(zeros(num,4),'VariableNames',{'loc','prev_loc','loc_time','collected'});
env = randi(10,10,10); env(1,1) = 0;
agent.loc = ones(num,1);
% Collect rewards one-by-one
agent.loc_time = ones(num,1);
tic
% Precompute random locations
random_locs = randi([2, numel(env)], num, time_limit);
for t = 1:time_limit
% Find agents that have reached their position at time t
active_agents_idx = find(agent.loc_time == t);
% Check for rewards at the agents' locations
rewards_available = env(agent.loc(active_agents_idx)) > 0;
% Update agents that found a reward
agents_with_reward_idx = active_agents_idx(rewards_available);
% Update agents that did not find a reward
agents_without_reward_idx = active_agents_idx(~rewards_available);
if ~isempty(agents_with_reward_idx)
[agent(agents_with_reward_idx,:), env] = return_with_reward(agent(agents_with_reward_idx,:), env);
end
if ~isempty(agents_without_reward_idx)
[agent(agents_without_reward_idx,:), env] = find_reward(agent(agents_without_reward_idx,:), env, random_locs(agents_without_reward_idx, t));
end
end
toc
Elapsed time is 0.497633 seconds.
function [agent,env] = find_reward(agent,env, random_locs)
agent.prev_loc = agent.loc;
% Use precomputed random locations
agent.loc = random_locs;
% Find time to get there
agent.loc_time = agent.loc_time + abs(agent.loc - agent.prev_loc);
end
function [agent,env] = return_with_reward(agent,env)
locs = agent.loc;
% Vectorized update to environment and agent properties
for loc = locs'
env(loc) = max(0, env(loc) - 1);
end
agent.collected = agent.collected + 1;
agent.prev_loc = locs;
% Return to starting position
agent.loc = ones(size(agent.loc)); % Assign an array of ones
% Find time to reach
agent.loc_time = agent.loc_time + abs(agent.loc - agent.prev_loc);
end
The optimized code runs 5 times faster than the original code by using the above methods.
You may refer to the following documentation links to have a better understanding on vectorization and precomputing arrays:
  1. https://www.mathworks.com/help/matlab/matlab_prog/preallocating-arrays.html
  2. https://www.mathworks.com/help/matlab/matlab_prog/vectorization.html

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!