I am currently attempting to calculate a specific type of set of locations within a grid. The problem at hand is related to a 2D packing optimization problem.
When packing items, I need to select a position (i,j)
in the grid for the item. Due to the item size, several other positions in the grid could also be covered. Therefore I am in need of a set Qijc
, which is the set of squares were placing an item c may cover position (i,j)
. For example if item c is sizes 2x2 the Qijc
contains {(i,j),(i-1,j-1),(i-1,j),(i,j-1)}
. If item c is in any of these positions.. position (i,j)
is also covered.
I have the current working code. However, it brute forces the calculation and is extremely slow when hitting grid sizes of 150x400. I have been trying to optimize the code, and I believe that I am missing something simple. Any suggestions would be appreciated.
Currently, I store the information in a dictionary in order to have a "one-to-many" relationship. Another caveat to the problem is that I only store positions for item c, that would cover position (i,j)
if the position is available in the network for item c.
In the given example, if item c = 3
, and we are looking at position (4,3)
the positions that would cover is (4,2)
and (4,3)
, however, position (5,3)
would also usually cover (4,3)
, however, is not stored as item c cannot go to this position. ( I hope this makes sense)
I believe that I have several redundant loops, and that it could be done in a much faster fashion, however, I struggle to wrap my head around it.
function validpositions(UnusuableSpace::Matrix{Int64}, nCargoes::Int64, SquaresL::Vector{Int64}, SquaresW::Vector{Int64})
# This function should return all position that are valid in the layout for
# cargo c in C. This should be returned as a tuple e.g. pos = [(1,1),(4,3),..,(18,1)].
N = []
for c in 1:nCargoesM
pos = Vector{Tuple{Int64,Int64}}()
for i in SquaresL[c]:size(UnusuableSpace)[1] # skip some of the rows. If the cargo has dimensions > 1.
for j in 1:size(UnusuableSpace)[2]
# Check if position includes a pillar / object
if UnusuableSpace[i,j] != 1
# Check if these is space for the cargo in the position.
if (i-SquaresL[c]) >= 0 && (j+SquaresW[c]-1) <= size(UnusuableSpace)[2]
# Check if position i,j covers an are with pillars in due to cargo
# dimensions.
if sum(UnusuableSpace[i-SquaresL[c]+1:i,j:j+SquaresW[c]-1]) == 0
push!(pos,(i,j))
end
end
end
end
end
push!(N,pos)
end
# return all valid positions of the cargo c.
return N
end # end valid position function
nCargoesM = 3
SquaresL = [1,2,3]
SquaresW = [1,2,2]
UnusableSpace = [
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 1 0 0 0
0 0 1 1 1 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
N = validpositions(UnusableSpace, nCargoesM, SquaresL, SquaresW)
function coveringSet(UnusableSpace::Matrix{Int64}, nCargoes::Int64, SquaresL::Vector{Int64}, SquaresW::Vector{Int64}, N)
Qijc = Dict{}()
for c in 1:nCargoesM
for i in 1:size(UnusableSpace)[1]
for j in 1:size(UnusableSpace)[2]
tmpset = []
for (k, l) in N[c]
# Get the points/nodes of the areas to check
vec1 = [i, j]
vec2 = [k-SquaresL[c]+1:k, l:l+SquaresW[c]-1]
tmp = [[x, y] for x in vec1[1], y in vec1[2]]
tpm = [[x, y] for x in vec2[1], y in vec2[2]]
# Check for overlapping
if sum([tmp in tpm for tmp = tmp]) > 0
push!(tmpset, [k, l])
end
end
push!(Qijc, [i, j, c] => tmpset)
end
end
end
return Qijc
end
Qijc = coveringSet(UnusableSpace, nCargoesM, SquaresL, SquaresW, N)