形状内分布线优化算法的选择

时间:2017-10-18 11:20:09

标签: algorithm optimization linear-programming

考虑具有钢筋和孔的混凝土板元件的以下表示。

Concrete slab with rebars and holes

我需要一种能够自动将线条分布在具有不同孔的任意形状上的算法。

主要限制因素是:

  1. 行不能在该区域之外或在孔内
  2. 两个并排线之间的距离不能超过变量D
  3. 行必须以固定间隔I定位,即y mod I = 0,其中y是行的Y坐标。
  4. 形状内的每个可用点都不能比D/2
  5. 更远

    我想通过最小化行总数 N 来优化解决方案。什么样的优化算法适合这个问题?

    我假设大多数方法都涉及将形状简化为光栅(像素高度 I )并禁用或启用每个像素。我认为这是一个明显的LP问题,并试图用GLPK设置它,但发现使用这个简化的栅格来描述任意数量的线很难。我也怀疑解决方案空间可能太大。

    我已经在C#中实现了一个算法来完成这项工作,但并没有非常优化。这是它的工作原理:

    1. 创建几何的简化栅格
    2. 使用复杂的公式计算每个单元格的分数,该公式考虑了可能的线路长度和与其他杆和障碍物的距离。
    3. 确定哪些需要加固(y方向的自由单元数> D
    4. 选择需要加固的得分最高的单元格,并在-x和+ x方向尽可能加强
    5. 重复
    6. 根据复杂的公式,这可以很好地工作,但在放置最后几行时会开始给出不需要的结果,因为它永远不能移动已经放置的行。 我还应该看看其他任何优化技术吗?

1 个答案:

答案 0 :(得分:2)

我不确定你想要的是什么 - 我相当确定它不是你的想法 - 但如果听起来合理,你可以尝试一下。

因为距离最多只是 d,并且可以是任何小于此值的东西,所以乍一看似乎贪婪的算法应该在这里起作用。始终放置下一行,以便(1)尽可能少,(2)它们尽可能远离现有的线。

假设您有一个针对此问题的最佳算法,并将下一行放在距离最后一行的距离a <= d处。说它放置b行。我们的贪婪算法肯定不会超过b行(因为第一个标准是尽可能少地放置),如果它放置b行,它会将它们放在距离c处使用a <= c <= d,因为它会尽可能地放置线条。

如果贪婪算法没有做到最佳算法所做的那样,那么它有以下几种方式的不同:

  1. 它将相同或更少的线放置得更远。假设最佳算法在下一步将b'行放置在距离a'处。然后这些行将在距离a+a'处,并且总共会有b+b'行。但是,在这种情况下,贪婪算法可以通过选择b'a+a'行置于位移c' = (a+a') - c来模拟最优算法。由于c > aa' < dc' < d这是合法的展示位置。

  2. 它将更少的线放在一起。这种情况实际上是有问题的。这可能会导致k不必要的行,如果任何放置需要至少k行,而最远的行需要更多,并且选择孔的排列以便(例如)它跨越的距离是d的倍数。

  3. 因此,贪婪算法在案例2中不起作用。但是,在其他情况下也是如此。特别是,我们在第一种情况下的观察非常有用:对于任何两个展示位置(distance, lines)(distance', lines'),如果是distance >= distance'lines <= lines',则首选展示位置始终是首选。这表明了以下算法:

    PlaceLines(start, stop)
    
        // if we are close enough to the other edge,
        // don't place any more lines.
        if start + d >= stop then return ([], 0)
    
        // see how many lines we can place at distance
        // d from the last placed lines. no need to
        // ever place more lines than this
        nmax = min_lines_at_distance(start + d)
    
        // see how that selection pans out by recursively
        // seeing how line placement works after choosing
        // nmax lines at distance d from the last lines.
        optimal = PlaceLines(start + d, stop)
        optimal[0] = [d] . optimal[0]
        optimal[1] = nmax + optimal[1]
    
        // we only need to try fewer lines, never more
        for n = 1 to nmax do
    
            // find the max displacement a from the last placed
            // lines where we can place n lines.
            a = max_distance_for_lines(start, stop, n)
    
            if a is undefined then continue
    
            // see how that choice pans out by placing
            // the rest of the lines
            candidate = PlaceLines(start + a, stop)
            candidate[0] = [a] . candidate[0]
            candidate[1] = n + candidate[1]
    
            // replace the last best placement with the
            // one we just tried, if it turned out to be
            // better than the last
            if candidate[1] < optimal[1] then
                optimal = candidate
    
        // return the best placement we found
        return optimal
    

    通过将结果(seq, lines)放入由(start, stop)索引的缓存中,可以通过 memoization 来改进这一点。这样,我们可以识别何时尝试计算可能已经过评估的分配。无论您是否对问题实例使用粗略或精细的离散化,我都希望我们能够解决这个问题。

    我不会详细了解max_lines_at_distancemax_distance_for_lines函数的工作方式,但可能会对这些函数有所了解。

    第一个告诉您在给定的位移处需要多少条线来跨越几何体。如果您的几何图形和彩色孔的像素是黑色的,那么这将意味着在指定的位移处查看单元格行,考虑连续的黑色线段,并从那里确定暗示了多少行。

    对于给定的候选行数,第二个告诉您与当前位置的最大距离,可以放置该行数。您可以通过告诉您可以放置​​或更少行数的最大距离来改善这一点。如果您使用此改进,则可以反转您重复n的方向,并且:

    1. 如果f(start, stop, x) = ay < x,您只需要从那时开始搜索a,而不是stop;
    2. 如果f(start, stop, x)未定义且y < x,则您不再需要搜索。
    3. 请注意,如果无法在nstart之间放置stop或更少的行,则可以取消定义此函数。

      另请注意,您可以单独记忆这些功能以保存重复查找。您可以为每行预先计算max_lines_at_distance并将其存储在缓存中以供日后使用。然后,max_distance_for_lines可以是一个循环,在两个边界内检查缓存前面。