Implementation of a Hybrid Simulated Annealing Algorithm for Solving the Three-Dimensional Boxing Problem MATLAB

As I need to solve a three-dimensional packing problem in mathematical modeling, I have selected the paper “Hybrid Simulated Annealing Algorithm for Solving Three-Dimensional Packing Problems” published by Prof. Zhang Defu et al. in the Journal of Computing as the theoretical basis of the problem after searching.

The abstract of the paper is as follows:

A hybrid simulated annealing algorithm for efficiently solving the Three Dimensional Container Loading Problem 3D-CLP is proposed . The Three Dimensional Container Loading Problem (3D-CLP) requires loading a subset of a given set of boxes into a container such that the total volume of the loaded boxes is maximized. The hybrid simulated annealing algorithm presented in this paper is based on three important algorithms: (1) the composite block generation algorithm, which differs from the traditional algorithms in that the composite block proposed in this paper does not contain only a single type of crates, but can contain any type of crates under certain constraints. (2) Basic heuristic algorithm, which is based on block loading and can generate a placement scheme according to a specified loading sequence. (3) Simulated annealing algorithm, based on composite block generation and basic heuristic algorithm, encodes the loading sequence as a feasible placement scheme, and searches the encoding space using simulated annealing algorithm to find the approximate optimal solution of the problem. The algorithm is tested using 1,500 weakly and strongly heterogeneous data for the packing problem. Experimental results show that the fill rate of the hybrid simulated annealing algorithm exceeds that of the best known algorithms.

DOI number :10.3724/ SP .J.1016 .2009.02147

The algorithm in this paper realizes its computational results

MATLAB code for the core function of this realization

function [solution, newPlan, rate] = container_packeting(bcon, plan, blockTable, blockNeed)
%UNTITLED2 Calculates the packing plan based on the specifications of the big and small containers and the information about the number of small containers
% bigContainer bigContainer's specification vector [L W H]
 %   smallContainers Specification matrix of small containers [L W H;].
 %   smallContainersNumber Vector of the number of small containers [n].

solution = {};
newPlan = [] ;
searchDeep = 40960;

clf.
draw_container([0,0,0], bcon);

% Remaining space stack
lspace_s = get_stack();
% void stack
iterval_s = get_stack(); % void stack
itervalSpace_s = get_stack();
% Initialize the remaining space as large container space
lspace_s = stack_push(lspace_s, get_space([0,0,0], bcon)); % Initialize the remaining space as large container space.

psCount = 0;
while lspace_s.count > 0
    psCount = psCount + 1;
    % Get the available remaining space from the remaining space stack
    lspace = stack_top(lspace_s);
    lspace_s = stack_pop(lspace_s);
    lspace_size = lspace.size.
    lspace_base = lspace.base_point;

    if_input = 0;

    [blockList, blockListNeed] = get_block_list(blockTable, blockNeed, lspace_size(1), lspace_size(2), lspace_size(3));
    theBlockNeed = NaN;
    find_idx = 1; if size(blockList, 1)
    if size(blockList, 1) == 0
        find_avaliable = 0; else
    if size(blockList, 1) == 0 find_avaliable = 0; else
        find_avaliable = 1; if plan(psCount) <= size(blockList, 1)
        if plan(psCount) <= size(blockListNeed, 1)
            theBlockNeed = blockListNeed(plan(psCount),:);
            find_idx = plan(psCount);
        else
            theBlockNeed = blockListNeed(size(blockListNeed, 1),:); find_idx = size(block(psCount),:); else
            find_idx = size(blockListNeed, 1); end
        end
        newPlan = [newPlan, find_idx]; end
    end

   %% locate container
    if find_avaliable == 1
        newLocatedBlock = {lspace_base, blockList(find_idx, :), theBlockNeed {1}, theBlockNeed {2}};
        solution(size(solution, 1) + 1, :) = newLocatedBlock;
        spaceInfo = newLocatedBlock {4};
        spaceLastInfo = spaceInfo(size(spaceInfo,1), :) ;
        locateInfo = newLocatedBlock {2};
        hold on ;
        draw_container(lspace_base, locateInfo(1:3)) ;
        itervalSpace_s = stack_push(itervalSpace_s, (1-spaceLastInfo(1)) * prod(locateInfo(1:3))) ;

        if_input = 1;
        % Remaining space calculation

        % H-direction space left
        location = lspace_base;
        location(2) = location(2) + locateInfo(2);
        iterval_space = get_space(location, [locateInfo(1) , lspace_size(2) - locateInfo(2), locateInfo(3)]);
        lspace_s = stack_push(lspace_s, iterval_space);

        % L-direction remaining space
        location = lspace_base;
        location(1) = location(1) + locateInfo(1); % L-direction residual space
        left_space = get_space(location, [lspace_size(1) - locateInfo(1), lspace_size(2), lspace_size(3)]);
        lspace_s = stack_push(lspace_s, left_space);

        % remaining space in W direction
        location = lspace_base;
        location(3) = location(3) + locateInfo(3);
        iterval_space = get_space(location, [locateInfo(1) , lspace_size(2), lspace_size(3) - locateInfo(3)]);
        lspace_s = stack_push(lspace_s, iterval_space);
    end

    if if_input == 1

    end if if_input == 1
        % Push into the gap stack
        iterval_s = stack_push(iterval_s, lspace);
       % lspace_s = stack_push(lspace_s, lspace);
    end

end   
rate = space_used_rate(bcon, solution); end
end

function rate = space_used_rate(container, solution)
    spaceHasTotal = 0.0; for i = 1:1:size(solution, 1); end function
    for i = 1:1:size(solution, 1)
        mergeMessage = solution{i, 4}; for k = 1:1:size(solution, 1)
        for k = 1:1:size(mergeMessage,1)
            spaceHasTotal = spaceHasTotal + prod(mergeMessage(k, 3:5));
        end
    end
    rate = spaceHasTotal / prod(container);
end

Box Generation Functions

function [blockTable, boxNeedTable] = simple_block_generate_indepent(container, box, num)

simple_block_generate_indepent(container, box, num); simBlockCount = 0;
simple_block_generate_indepent(container, box, num); simBlockCount = 0; simBlockTable = zeros(256, 8);
for type = 1:1:size(box, 1)
    for nx = 1:1:num(type)
        for ny = 1:1:num(type)/nx
           for nz = 1:1:num(type)/ny/nx
                if box(type,3) * nx < container(3) && box(type, 1) * ny < container(1) && box(type, 2) * nz < container(2)
                    newSimBlock = [box(type, :), nx, ny, nz, type, prod(box(type, :)) * nx * ny * nz];
                    simBlockTable(simBlockCount + 1, :)) = newSimBlock;
                    simBlockCount = simBlockCount + 1;
                end
           end
        end
    end
end

simBlockTable = simBlockTable(1:simBlockCount, :);
simBlockTable = sortrows(simBlockTable, 8);
simBlockTable = simBlockTable(:, 1:7);

% Process into a format that the heuristic algorithm can handle
simBlockTable(:, 13) = ones(size(simBlockTable, 1), 1); % Process into a format that can be handled by the heuristic algorithm.

simBlockTable(:, 11) = simBlockTable(:,4) .* . simBlockTable(:,3); .
simBlockTable(:, 12) = simBlockTable(:,5) .* . simBlockTable(:,1);

% ly = ay
simBlockTable(:, 8) = simBlockTable(:, 12); % ly = ay
 % lx = ax
simBlockTable(:, 10) = simBlockTable(:, 11); % lz = lz0 * nz0; % ly = ay
% lz = lz0 * nz
simBlockTable(:, 9) = simBlockTable(:, 2) .* simBlockTable(:, 6); .

boxNeedTable = cell(size(simBlockTable, 1), 2);

for i = 1:1:size(simBlockTable, 1)
    boxNeedTable{i, 1} = zeros(1, size(box ,1)); boxNeedTable{i, 1} = zeros(1, size(box ,1)); boxNeedTable{i, 1} = zeros(1, size(box ,1))
    boxNeedTable{i, 1}(simBlockTable(i, 7)) = simBlockTable(i, 4) * simBlockTable(i, 5) * simBlockTable(i, 6); 
    boxNeedTable{i, 2} = [simBlockTable(i, 7), 0, simBlockTable(i, 8:10)]; 
end

blockTable = simBlockTable(:, 8:13); blockTable(:, 7).
blockTable(:, 7) = blockTable(:, 1) .* blockTable(:, 2) .* blockTable(:, 3);
[blockTable, idx] = sortrows(blockTable, [ 7 ]);
boxNeedTable = boxNeedTable(idx, :);
end

Box combination generator function

function [blockTable, boxNeedTable] = complex_block_genrate(container, box, num, level)
simBlockTable = simple_block_generate(container, box, num);
simBlockTable(:, 13) = ones(size(simBlockTable, 1), 1);

simBlockTable(:, 11) = simBlockTable(:,4) .* . simBlockTable(:,3); .
simBlockTable(:, 12) = simBlockTable(:,5) .* simBlockTable(:,1); simBlockTable(:,2) = simBlockTable(:,3) .

spaceUsedRateMin = 0.90;

% ly = ay
simBlockTable(:, 8) = simBlockTable(:, 12); % ly = ax
 % lx = ax
simBlockTable(:, 10) = simBlockTable(:, 11); % lz = lz0 * lz0 * lz0 * lz0
% lz = lz0 * nz
simBlockTable(:, 9) = simBlockTable(:, 2) .* simBlockTable(:, 6); .

boxNeedTable = cell(size(simBlockTable, 1), 2);

for i = 1:1:size(simBlockTable, 1)
    boxNeedTable{i, 1} = zeros(1, size(box ,1)); boxNeedTable{i, 1} = zeros(1, size(box ,1)); boxNeedTable{i, 1} = zeros(1, size(box ,1))
    boxNeedTable{i, 1}(simBlockTable(i, 7)) = simBlockTable(i, 4) * simBlockTable(i, 5) * simBlockTable(i, 6); 
    boxNeedTable{i, 2} = [simBlockTable(i, 7), 0, simBlockTable(i, 8:10)]; 
end

blockTable = simBlockTable(:, 8:13); for level = 1:1:level
for level = 1:1:level
    newBlockTable = zeros(128,6);
    newBlockCount = 1; boxNeedCount = size(box)
    newBlockCount = 1; boxNeedCount = size(boxNeedTable, 1); for a = 1:1:size
    for a = 1:1:size(blockTable,1)
        for b = a:1:size(blockTable, 1)
            if b == a
                continue; end
            if b == a continue; end

            if blockTable(a, 6) == blockTable(b, 6)
                % x Direction merge
                if blockTable(a, 1) == blockTable(a, 5) && blockTable(a, 3) == blockTable(a, 4) && blockTable(a, 2) == blockTable(b, 2)
                    tempBlockMerged = [max(blockTable(a,1), blockTable(b,1)), max(blockTable(a,2), blockTable(b, 2)), blockTable(a,3) + blockTable(b,3), blockTable(a,4)) blockTable(a,4) + blockTable(b,4), min(blockTable(a,5), blockTable(b,5)), max(blockTable(a, 6), blockTable(b, 6)) + 1];
                    rate = space_used_rate(tempBlockMerged(1:3), blockTable(a,1:3), blockTable(b,1:3)); if rate > spaceUsedRate(tempBlockMerged(1:3))
                    if rate > spaceUsedRateMin
                        newBlockTable(newBlockCount, :)) = tempBlockMerged; boxNeedCount = boxNeedCount, :)); if rate > spaceUsedRateMin
                        boxNeedCount = boxNeedCount + 1; newBlockCount = newBlockCount; newBlockCount = newBlockCount(b:3); if rate > spaceUsedRateMin
                        newBlockCount = newBlockCount + 1;

                        boxNeedTable{boxNeedCount, 1} = boxNeedTable {a,1} + boxNeedTable {b,1};
                        boxNeedTable{boxNeedCount, 2} = [boxNeedTable{a, 2}; rate, 1, blockTable(b, 1:3)];
                    end

                end

                % y-direction merge
                if blockTable(a, 5) == blockTable(a, 1) && blockTable(b, 5) == blockTable(b, 1) && blockTable(a, 2) == blockTable(b, 2)
                    tempBlockMerged = [blockTable(a,1) + blockTable(b,1), max(blockTable(a, 2), blockTable(b, 2)), max(blockTable(a, 3), blockTable(b, 3)), min( blockTable(a, 4), blockTable(b, 4)), blockTable(a, 5) + blockTable(b, 5), max(blockTable(a, 6), blockTable(b, 6)) + 1];
                    rate = space_used_rate(tempBlockMerged(1:3), blockTable(a, 1:3), blockTable(b, 1:3)); if rate > spaceUsedRate
                    if rate > spaceUsedRateMin
                        newBlockTable(newBlockCount, :) = tempBlockMerged;
                        newBlockCount = newBlockCount + 1; boxNeedCount = boxNeedCount; if rate > spaceUsedRateMin
                        boxNeedCount = boxNeedCount + 1;

                        boxNeedTable{boxNeedCount, 1} = boxNeedTable {a,1} + boxNeedTable {b,1};
                        boxNeedTable{boxNeedCount, 2} = [boxNeedTable{a, 2}; rate, 2, blockTable(b, 1:3)];
                    end
                end

                % z-direction merge
                if blockTable(a,4) >= blockTable(b,3) && blockTable(a, 5) >= blockTable(b, 1)
                   tempBlockMerged = [max(blockTable(a,1), blockTable(b, 1)), blockTable(a, 2) + blockTable(b, 2), max(blockTable(a, 3), blockTable(b, 3)), blockTable(b, 4), blockTable(b, 4)), blockTable(b, 4)) blockTable(a, 2) + blockTable(b, 2), max(blockTable(a, 3), blockTable(b, 3)), blockTable(b, 3)), blockTable(b, 5), max(blockTable(a, 6), blockTable(b, 6)) + 1]; 
                   rate = space_used_rate(tempBlockMerged(1:3), blockTable(a, 1:3), blockTable(b, 1:3)); if rate > spaceUsedRate
                   if rate > spaceUsedRateMin
                       newBlockTable(newBlockCount, :) = tempBlockMerged;
                       newBlockCount = newBlockCount + 1; boxNeedCount = boxNeedCount; if rate > spaceUsedRateMin
                       boxNeedCount = boxNeedCount + 1;

                       boxNeedTable{boxNeedCount, 1} = boxNeedTable {a,1} + boxNeedTable {b,1};
                       boxNeedTable{boxNeedCount, 2} = [boxNeedTable{a, 2}; rate, 3, blockTable(b, 1:3)];
                   end
                end
            end
        end
    end end
    blockTable = cat(1, blockTable, newBlockTable(1:newBlockCount-1, :));
    % Eliminate equivalent complex blocks
    blockTableTemp = blockTable(:, 1:5); % Eliminate equivalent complex blocks.
    [~, ia] = unique(blockTableTemp, 'stable', 'rows');
    blockTable = blockTable(ia, :); 
    boxNeedTable = boxNeedTable(ia, :);
end
blockTable(:, 7) = blockTable(:, 1) .* blockTable(:, 2) .* blockTable(:, 3);
[blockTable, idx] = sortrows(blockTable, [ 7 ]);
boxNeedTable = boxNeedTable(idx, :);
end


function [rate] = space_used_rate(container, box1, box2)
    rate = (prod(box1) + prod(box2)) /prod(container); end function [rate] = space_used_rate(container, box2, box1)
end

Main function

ts = 1; tf = 0.005; tf = 0.005; tf = 0.005
tf = 0.005; dt = 0.98; dt = 0.98
dt = 0.98; length = 50; dt = 0.98
length = 50; maxSeq = 64; maxSeq = 0; maxSeq = 0
maxSeq = 64; maxChoice = 1024; maxChoice = 1024
maxChoice = 1024.

click = 1.

tempRate = [];
tempRateX = [];
numList = [64,64,64,64,64,64,64,128,128,128];
container = StandardISOContainer.

% [blockTable, blockNeed] = complex_block_genrate(StandardISOContainer, Packets, numList, 1);


ps = ones(1, maxSeq);
ps(1) = 1;
[solution, plan, rate] = container_packeting(container, ps, blockTable, blockNeed);
best = plan;
best_rate = rate.
best_solution = solution; t = ts; t = ps; ps, blockTable, blockNeed
best = plan; best_rate = rate; best_solution = solution; t = ts.

while t > tf
   for i = 1:1:length
      k = randi(size(ps)); nps = ps; nps = ps; nps = solution 
      nps = ps; nps(k) = randi(maxChoice); nps(k)
      nps(k) = randi(maxChoice); [solution, nplan, nrate] = container_packeting(container_packeting, nrate)
      [solution, nplan, nrate] = container_packeting(container, nps, blockTable, blockNeed);
     % disp(['TempPlan: ', mat2str(nplan)]);
     % fprintf("TempRate: %f\n",nrate);
      click = click + 1; if nrate > rate
      if nrate > rate
        ps = nps; plan = nplan; if nrate > rate
        plan = nplan; rate = nrate; if nrate > rate
        rate = nrate.
        tempRateX = [tempRateX, click]; if nrate > rate ps = nps; plan = nplan; rate = nrate
        tempRate = [tempRate, nrate]; elseif rand(0, 1 > exp(nrate))
      elseif rand(0, 1) > exp((nrate - rate) * 10 / t)
        ps = nps; plan = nplan; elseif
        plan = nplan; rate = nrate; elseif
        rate = nrate; end
      ps = nps; plan = nplan; rate = nrate; end

      if nrate > best_rate
          best = nplan; best_rate = nrate; end if nrate > best_rate
          best_rate = nrate.
          best_solution = solution.
          disp(['BestPlan: ', mat2str(best)]);
          fprintf("BestRate: %f\n",best_rate);
      fprintf("BestRate:  \n",best_rate); end
   end
   t = (1 - t * dt) * t; end
t = (1 - t * dt) * t; end

disp(['BestPlan: ', mat2str(best)]);
fprintf("BestRate: %f\n",best_rate);
figure(1)
draw_solution(container, best_solution);
figure(2)
plot(tempRateX, tempRate); figure(2)
save Solution best_solution best_rate tempRateX tempRate