【问题标题】:Google OR-Tools bin-packing problem: struggling to add constraint such that all items packed in bin MUST have same delivery destinationGoogle OR-Tools 装箱问题:努力添加约束,以便装在箱中的所有物品必须具有相同的交付目的地
【发布时间】:2022-12-17 16:29:47
【问题描述】:

正如标题所示,我正在使用 Google OR-Tools 来解决装箱问题。我想要求装在给定卡车中的所有订单都具有相同的交货目的地。以下是我尝试实现这一点,但似乎没有用:

# x[i, j] = 1 if item i is packed in bin j

x = {}
for i in data['orders']:
    for j in data['trucks']:
        x[(i, j)] = solver.IntVar(0, 1, 'x_%i_%i' % (i, j))

data['trucks'] = [0, 1, 2, 3, ...]
data['orders'] = [0, 1, 2, 3, ...]
data['delivery_county_id'] = [8, 8, 8, 1, 3, 2, ...]

from itertools import groupby

# Checks if all elements of list are equal
def all_equal(iterable):
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

for j in data['trucks']:
    solver.Add( all_equal ( [ x[(i, j)] * data['delivery_county_id'][i] for i in data['orders'] if x[(i, j)] == 1 ] ) == True )

奇怪的是,我在执行代码时没有收到任何错误,但我的约束没有得到遵守。我不确定为什么会这样。任何帮助或建议将不胜感激!

【问题讨论】:

  • 在最后一行代码中,您将重载的 IntVar 运算符与 Python 运算符混合在一起,因此约束根本没有按照您的想法进行。我的建议是,如果卡车 j 中有 k 县的订单,则创建另一个数组 y[j, k] = 1。然后为 y[j, k] 添加约束 MaxEquality 作为所有 i 的 x[i, j] 的最大值,其中 data['delivery_county_id'][i] == k 以确保 y 具有正确的值,然后为每辆卡车 j (所有 k 的 y[j,k] 之和) <= 1。
  • @ChristopherHamkins 您能否分享代码的外观?我正在努力将其翻译成 python。我目前正在运行求解器 n 次,其中 n 是目的地的数量。这意味着我将数据集拆分为单独的数据集,并为每个数据集运行一次求解器。您提出的解决方案似乎是更好的答案。

标签: knapsack-problem or-tools mixed-integer-programming bin-packing


【解决方案1】:

我没有有效的 Python 安装,但这是在 c# 中完成的方式:

       public void initModel(CpModel model)
        {
            // Make up some data for the counties of the orders
            deliveryCountyId = new int[nOrders];
            for (int order = 0; order < nOrders; order++)
            {
                deliveryCountyId[order] = order % nCounties;
            }

            // Boolean variables for item shipped by truck
            x = new IntVar[nOrders, nTrucks];
            for (int order = 0; order < nOrders; order++)
            {
                for (int truck = 0; truck < nTrucks; truck++)
                {
                    x[order, truck] = model.NewBoolVar($"Item {order} (county {deliveryCountyId[order]}) in truck {truck}");
                }
            }

            // Boolean variables for truck carrying an item for county
            y = new IntVar[nTrucks, nCounties];
            for (int truck = 0; truck < nTrucks; truck++)
            {
                for (int county = 0; county < nCounties; county++)
                {
                    y[truck, county] = model.NewBoolVar($"Truck {truck} has item for county {county}");
                }
            }

            // Each item must be shipped by exactly one truck
            for (int order = 0; order < nOrders; order++)
            {
                List<IntVar> trucksForThisItem = new List<IntVar>();
                for (int truck = 0; truck < nTrucks; truck++)
                {
                    trucksForThisItem.Add(x[order, truck]);
                }
                model.Add(LinearExpr.Sum(trucksForThisItem) == 1);
            }

            // Compute which counties are in each truck
            for (int truck = 0; truck < nTrucks; truck++)
            {
                for (int county = 0; county < nCounties; county++)
                {
                    List<IntVar> ordersForCountyAndTruck = new List<IntVar>();
                    {
                        for (int order = 0; order < nOrders; order++)
                        {
                            if (deliveryCountyId[order] == county)
                            {
                                ordersForCountyAndTruck.Add(x[order, truck]);
                            }
                        }
                    }
                    if (ordersForCountyAndTruck.Count > 0)
                    {
                        model.AddMaxEquality(y[truck, county], ordersForCountyAndTruck);
                    }
                    else
                    {
                        model.Add(y[truck, county] == 0);
                    }
                }
            }

            // Each truck may carry items for only one county
            for (int truck = 0; truck < nTrucks; truck++)
            {
                List<IntVar> countiesPerTruck = new List<IntVar>();
                for (int county = 0; county < nCounties; county++)
                {
                    countiesPerTruck.Add(y[truck, county]);
                }
                model.Add(LinearExpr.Sum(countiesPerTruck) <= 1);
            }
        }
    }

您可以轻松地用 Python 表达等效的方法调用。

【讨论】:

    【解决方案2】:

    我使用了 Google-ortool 的 CP-SAT 求解器(python)。请看下面的代码,我添加了所需的约束

    import random
    from ortools.sat.python import cp_model as cp
    
    trucks = list(range(1, 9))
    orders = list(range(1, 51))
    delivery_county_id = [random.randint(1, 8) for _ in orders]
    
    order_country = list(zip(orders, delivery_county_id))
    
    model = cp.CpModel()
    
    dv_order_truck = {}
    for ord_cntry in order_country:
        for trck in trucks:
            dv_order_truck[(ord_cntry, trck)] = model.NewBoolVar("")
            
    # one order in one truck only
    for ord_cntry in order_country:
        model.Add(sum(dv_order_truck[(ord_cntry, trck)] for trck in trucks) == 1)
        
    # all orders packed into a given truck have the same delivery destination
    dv_truck_country = {}
    for trck in trucks:
        for cntry in set(delivery_county_id):
            dv_truck_country[trck, cntry] = model.NewBoolVar("")
           
    for trck in trucks:
        for cntry in set(delivery_county_id):
            orders_inTruck_cntry = [v for k,v in dv_order_truck.items() if k[1] == trck and k[0][1] == cntry]
            model.AddMaxEquality(dv_truck_country[trck, cntry], orders_inTruck_cntry)
            
    for trck in trucks:
        model.Add(sum(dv_truck_country[trck, cntry] for cntry in set(delivery_county_id)) == 1)
        
    solver = cp.CpSolver()
    solver.Solve(model)
    
    # inspect the solution
    solution = [(ord_cntry, trck) for ord_cntry in order_country for trck in trucks if solver.Value(dv_order_truck[(ord_cntry, trck)]) > 0]
    sorted(solution, key = lambda x : x[0][1],reverse=True)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-17
      • 2012-03-22
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 2011-05-29
      相关资源
      最近更新 更多