在 Julia 网格系统性能问题中查找重叠区域

Finding overlapping areas in Julia grid system performance question

我目前正在尝试计算网格中一组特定类型的位置。手头的问题与二维打包优化问题有关。

打包物品时,我需要在物品的网格中select一个位置(i,j)。由于项目大小,网格中的其他几个位置也可能被覆盖。因此我需要一组 Qijc,这是一组正方形,其中放置一个项目 c 可能覆盖位置 (i,j)。例如,如果项目 c 的尺寸为 2x2,则 Qijc 包含 {(i,j),(i-1,j-1),(i-1,j),(i,j-1)}。如果项目 c 在这些位置中的任何一个.. 位置 (i,j) 也被覆盖。

我有当前的工作代码。然而,它会强制执行计算,并且在达到 150x400 的网格大小时非常慢。我一直在努力优化代码,我相信我遗漏了一些简单的东西。如有任何建议,我们将不胜感激。

目前,我将信息存储在字典中以实现“一对多”关系。该问题的另一个警告是我只存储项目 c 的位置,如果该位置在网络中可用于项目 c,那么它将覆盖位置 (i,j)

在给定的示例中,如果项目 c = 3,并且我们正在查看位置 (4,3),那么将覆盖的位置是 (4,2)(4,3),但是,位置(5,3) 通常也会覆盖 (4,3),但是不会存储,因为项目 c 无法到达此位置。 (我希望这是有道理的)

我相信我有几个冗余循环,并且可以以更快的方式完成,但是,我很难理解它。

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)


我实际上在一段时间后自己解决了这个问题。您可以预先计算字典中的所有键并穿线循环。检查货物的位置,是否是允许的位置。

function coveringSet_new_threaded(UnusableSpace, nCargoesM::Int64, SquaresL::Vector{Int64}, SquaresW::Vector{Int64})
    # Create dictionary
    Qijc4 = Dict{}()

    for c in 1:nCargoesM
        for i in 1:size(UnusableSpace)[1]
            for j in 1:size(UnusableSpace)[2]
                push!(Qijc4, [i, j, c] => [])
            end
        end
    end

    # Finding the combinations of cargo size
    combinationsCargo = Vector{Tuple{Int64,Int64}}()
    for i in 1:length(SquaresL)
        push!(combinationsCargo, (SquaresL[i], SquaresW[i]))
    end

    # The unique combinations available
    CargoTypes = unique(combinationsCargo)


    Threads.@threads for c in 1:length(CargoTypes)
        typeindx = findall(x -> x == CargoTypes[c], combinationsCargo)
        # Index to control where to find information regarding squaresL and squaresW
        sizeidx = typeindx[1]

        #Threads.@threads for c in 1:nCargoesM
        for i in 1:size(UnusableSpace)[1]
            for j in 1:size(UnusableSpace)[2]
                tmpset = []

                # Generate the range of positions to check. (h,m) check if it also covers (i,j)
                # due to cargo size.
                for h in i:i+SquaresW[sizeidx]-1
                    for m in j-SquaresL[sizeidx]+1:j
                        # Check that the position is actually within the layout of the ship
                        if (h > 0 && m > 0 && h <= size(UnusableSpace)[1] && h <= size(UnusableSpace)[2])
                            # Check that the position is not unusable.
                            if UnusableSpace[h, m] != 1
                                # Check that the position given cargo size is withon the layout of the ship.
                                if (h - SquaresW[sizeidx]) >= 0 && (m + SquaresL[sizeidx] - 1) <= size(UnusableSpace)[2]
                                    # Check that the cargo, when in position (h,m) does not collide with any unusable space.
                                    if sum(UnusableSpace[h-SquaresW[sizeidx]+1:h, m:m+SquaresL[sizeidx]-1]) == 0
                                        # Only then is it a position for cargo c that covers (i,j).
                                        push!(tmpset, [h, m])
                                    end
                                end
                            end
                        end
                    end
                end
                # Push in set for that position. It may be empty.
                for k in typeindx
                    Qijc4[[i, j, k]] = tmpset
                end
            end
        end
    end

    return Qijc4
end