微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Python OR-Tools 点之间的距离

如何解决Python OR-Tools 点之间的距离

我正在使用 or-tools 约束求解器来查找房间中物品的工作位置。我使用 CP 求解器而不是背包求解器,因为我需要添加额外的约束。

我将每个项目表示为 x 区间和 y 区间,并添加如下约束:

model.AddNoOverlap2D(x_intervals,y_intervals)

这有助于放置对象以使它们不重叠,但我需要添加一个约束以确保对象之间存在一定距离。这应该是对象之间的基本 2D 距离,但此公式需要 sqrt 和 pow 函数,而 Intvar 项似乎无法使用这些函数

我曾考虑使用另一个以每个主要对象为中心的“间隔对象”,并添加一个 NoOverlap2D 约束,但这会导致当距离公式更精确的距离,不会浪费房间内的空间。

编辑 - 下面的代码现在用于对项目设置距离约束。

在 Laurent 的建议之后,我尝试制作许多中间变量来处理这个问题,但我坚持乘以或除以定义形状位置间隔的 Intvar

# Now lets make all possible combinations and make a distance between them
combos = list(combinations(range(len(rects_data)),2))

print(combos) 

currentdistanceId = 0

distanceVariables = []

for listSet in combos:
    leftItem = all_vars[listSet[0]]
    rightItem = all_vars[listSet[1]]

    if leftItem.holderType == HolderType.Person and rightItem.holderType == HolderType.Person:
        print(f"Adding distances between {listSet[0]} and {listSet[1]} because both are people")
        
        currentdistanceId = currentdistanceId + 1

        # Add an intermediate variable to store the sum of x for the center of left object
        leftCenterXSum = model.NewIntvar(0,horizon.x*2,f"leftCenterXSum{currentdistanceId}")
        # Add constraint to it
        model.Add(leftCenterXSum == leftItem.x2 + leftItem.x1)
        # Add an intermediate variable to store the center of x of the left object
        leftCenterX = model.NewIntvar(0,horizon.x,f"leftCenterX{currentdistanceId}")
        # Add a constraint to divide it by 2 to make it te center
        model.AddDivisionEquality(leftCenterX,leftCenterXSum,2)

        ## Repeat for x and y for left and right objects
        leftCenterYSum = model.NewIntvar(0,horizon.y*2,f"leftCenterYSum{currentdistanceId}")
        model.Add(leftCenterYSum == leftItem.y2 + leftItem.y1)
        leftCenterY = model.NewIntvar(0,horizon.y,f"leftCenterY{currentdistanceId}")
        model.AddDivisionEquality(leftCenterY,leftCenterYSum,2)

        rightCenterXSum = model.NewIntvar(0,f"rightCenterXSum{currentdistanceId}")
        model.Add(rightCenterXSum == rightItem.x2 + rightItem.x1)
        rightCenterX = model.NewIntvar(0,f"rightCenterX{currentdistanceId}")
        model.AddDivisionEquality(rightCenterX,rightCenterXSum,2)

        rightCenterYSum = model.NewIntvar(0,f"rightCenterYSum{currentdistanceId}")
        model.Add(rightCenterYSum == rightItem.y2 + rightItem.y1)
        rightCenterY = model.NewIntvar(0,f"rightCenterY{currentdistanceId}")
        model.AddDivisionEquality(rightCenterY,rightCenterYSum,2)

        # Create variable for difference of x
        xDiff = model.NewIntvar(-horizon.x,f"xDiff{currentdistanceId}")

        # Create constraint for difference of x
        model.Add(xDiff == rightCenterX - leftCenterX)

        # Create variable for difference of y
        yDiff = model.NewIntvar(-horizon.y,f"yDiff{currentdistanceId}")

        # Create constraint for difference for y
        model.Add(yDiff == rightCenterY - leftCenterY)

        # Create variables for x and y squared
        xDiffSquared = model.NewIntvar(0,horizon.x**2,f"xDiffSquared{currentdistanceId}")
        yDiffSquared = model.NewIntvar(0,horizon.y**2,f"yDiffSquared{currentdistanceId}")

        # Add constraint to multiply them
        model.AddMultiplicationEquality(xDiffSquared,[xDiff,xDiff])
        model.AddMultiplicationEquality(yDiffSquared,[yDiff,yDiff])

        totaldistance = model.NewIntvar(0,horizon.x**2 + horizon.y**2,f"totaldistance{currentdistanceId}")

        model.Add(totaldistance == xDiffSquared + yDiffSquared)

        distanceVariables.append(totaldistance)

        model.Add( totaldistance >= distanceSquared )
    else:
        print(f"Skipping distances between {listSet[0]} and {listSet[1]} because one is furniture")

解决方法

代替

M : 2
F : 2

你为什么不写

Sqrt((x1-x2)^2 + (y1-y2)^2) >= d

支持。你需要写(用伪代码)

(x1-x2)^2 + (y1-y2)^2 >= d^2

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。