简体   繁体   English

Google OR-Tools 装箱问题:努力添加约束,以便装在箱中的所有物品必须具有相同的交付目的地

[英]Google OR-Tools bin-packing problem: struggling to add constraint such that all items packed in bin MUST have same delivery destination

As the title suggests, I am using Google OR-Tools to tackle a bin-packing problem.正如标题所示,我正在使用 Google OR-Tools 来解决装箱问题。 I would like to require that all orders packed into a given truck have the same delivery destination.我想要求装在给定卡车中的所有订单都具有相同的交货目的地。 The following is my attempt at implementing this, which doesn't seem to be working:以下是我尝试实现这一点,但似乎没有用:

# 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 )

Strangely, I am not getting any errors when I execute the code, but my constraint is not being obeyed.奇怪的是,我在执行代码时没有收到任何错误,但我的约束没有得到遵守。 I'm not sure why that is.我不确定为什么会这样。 Any assistance or suggestions would be profoundly appreciated!任何帮助或建议将不胜感激!

I don't have a working Python installation, but this is how it could be done in c#:我没有有效的 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);
            }
        }
    }

You can easily express the equivalent method calls in Python.您可以在 Python 中轻松表达等效的方法调用。

I have used Google-ortool's CP-SAT solver (python).我使用了 Google-ortool 的 CP-SAT 求解器(python)。 Please see the code below, I have added the desired constraint请看下面的代码,我添加了所需的约束

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM