【问题标题】:What makes this code faster?是什么让这段代码更快?
【发布时间】:2014-05-16 23:52:17
【问题描述】:

我正在 Matlab 中实现一维装箱问题 (BPP) 的第一次拟合 (FF) 启发式。

在算法的第一次实现之后,我尝试改进我的代码,最终我得到了我认为更好的第二次实现,因为在我看来它更加优雅

我的好奇心(让我说我是一个完美主义者)引导我运行并比较这两种实现。他们得到了完全相同的结果(应该是这样),但我的第一个实现要快 10 倍以上!

我的问题是:你能帮我找出原因吗?第二个实现的哪一部分拖慢了我的代码?

第一次实施:

function packing = firstFit(items)

global N_items bin_size

item_assign = zeros(N_items,1);
residual = bin_size*ones(N_items,1);
tmp = residual;

% Assign each item on the list to a bin
for i = 1:N_items
    j = 1; % always start by trying the first bin
    % Repeat until the item is assigned to a bin
    while true
        if items(i) > residual(j)
            j = j+1; % try to fit it in the next bin 
        else
            residual(j) = residual(j)-items(i);
            item_assign(i) = j;
            break
        end
    end
end

% Check how many bins were needed to accommodate all items
N_bins = N_items - sum(residual == tmp);

packing = cell(N_bins,3);
for i = 1:N_bins
    packing{i,1} = item_assign == i;
    packing{i,2} = items(packing{i,1});
    packing{i,3} = residual(i);
end

end

第二次实施:

function packing = firstFit2(items)

global N_items bin_size

% Initialize 1st bin
packing{1,1} = false(N_items,1);
packing{1,3} = bin_size;
N_bins = 1;

% Assign each item on the list to a bin
for i = 1:N_items
    % Look for the first bin able to hold this item
    j = find(cell2mat(packing(:,3)) >= items(i),1);
    if isempty(j)
        % Create a new empty bin if necessary
        j = N_bins + 1;
        packing{j,1} = false(N_items,1);
        packing{j,3} = bin_size;
        N_bins = j;
    end
    % Assign item to that bin
    packing{j,1}(i) = true;
    packing{j,2} = [packing{j,2};items(i)];
    packing{j,3} = packing{j,3} - items(i);
end

end

结果:

对于给定的数据集,第一个实现的运行时间约为 0.011 秒,而第二个实现的运行时间约为 0.13 秒。

如果你愿意,我可以为你提供数据集,请告诉我。

BPP 的简要说明:

有一组项目,每个项目都有一个特征长度。这些物品应装入一组固定大小的箱子中。目标是使用尽可能少的箱子来包装所有物品。

FF启发式的简要说明:

First-Fit (FF) 启发式背后的想法非常简单:

  1. 项目是按顺序考虑的,每个项目都位于可以容纳它的第一个箱子中。
  2. 用剩余容量 R=C 初始化一个 bin,当将一个项目放入其中时,剩余容量会减少该项目的大小。
  3. 如果所有打开的垃圾箱都无法容纳物品,则会创建一个新的空垃圾箱。

【问题讨论】:

  • 我敢说是分配时间。在第一个解决方案中,一次性创建所有垃圾箱packing = cell(N_bins,3);,在第二个解决方案中,您一个一个地创建它们。它看起来可能无害,但每次扩大packing 的限制时,必须分配一个能够容纳所有数据的新内存块,然后必须将旧packing 的内容复制到新内存中。
  • 使用matlab命令profile分析性能。
  • 更简单的代码可能更容易进行 JIT 优化——尤其是在涉及多个循环时。我想知道所有对cell2mat 的调用是否也会影响性能……分析器会告诉你这些事情。

标签: matlab


【解决方案1】:

您的代码比它需要的复杂得多。很难说为什么一种实现比另一种更快,因为 MATLAB 在幕后进行了各种优化。循环,尤其是在循环中更改向量的大小(就像您在第二个代码中所做的那样)通常很慢。

干净的 MATLAB 方法看起来像

%% do the actual work
binSize = 20;
itemMaxSize = 10;
numItems = 10;

items = randi(itemMaxSize, numItems, 1);

R = binSize * ones(numItems, 1); % there can not be more bins than items
assignment = zeros(numItems, 1);

for i = 1:numItems
    assignment(i) = find( R >= items(i), 1, 'first');
    R(assignment(i)) = R(assignment(i)) - items(i);

end

R = R( R < binSize );

%% make a figure
figure
hold on
for i = 1:length(R)
    itemInds = find(assignment == i);
    sizes = items(itemInds);

    plot(i, cumsum(sizes), '*')
    text(i * ones(size(sizes)) + .1, cumsum(sizes), num2str(itemInds))
end


ylim([0 round(binSize*1.1)])
plot([.5 length(R)+.5], [binSize binSize], '--')
xlim([.5, length(R)+.5]);
set(gca, 'xtick', 1:length(R))
xlabel('bin ind')
ylabel('fill')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 2014-09-14
    • 2011-05-27
    • 1970-01-01
    • 2016-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多