ortools 中的特定约束太慢了

问题描述

我有一个分配问题要解决。我发现 ortools 是一个很好的工具,可以在这里使用。我设法解决了它,但它很慢,我需要它快。

我遇到的问题基本上是一堆商店以不同的价格出售相同的商品。我需要选择从哪里挑选这些商品,以达到最低的总价以及不超过 4 家商店。

这是我的代码,但如果提供的成本矩阵有 4 个以上的商店,它会很慢。问题在于商店最大限制约束。无论如何,这可以通过不同的编码来提高速度吗?

import numpy as np
from ortools.sat.python import cp_model
from ortools.linear_solver import pywraplp

#cost matrix,where j are stores,i are items

C = np.array([[38,13,73,10,76,6,80,65,17,2],[77,72,7,26,51,21,19,85,12,29],[30,15,69,88,95,97,87,14],[10,8,64,62,23,58,2,1,61,82],[ 9,89,14,48,31,4,71,22],[50,25,44,77,27,53,81],[42,83,16,99,27],[26,68,24,28,38,84,39],33,35,11,93],[75,63,47,56,66,78,4],[ 1,86,3,92,[76,37],[ 8,46,75,93,61],[25,98,55,83],[87,67,49,18,43],[21,54,56],[62,57,90,22,85],[44,60,72],[54,70,37,41,50,78]])

# the solver func
def Solve_Cost_Matrix_2(cost):
    
    model = cp_model.CpModel()
    max_stops=4
    
    #generate ranges

    num_items = len(cost)
    num_shops = len(cost[0])

    all_items = range(num_items)
    all_shops = range(num_shops)


    

    # Create bool Variable matrix
    x=[]
    for i in all_items:
        t=[]
        for j in all_shops:
            t.append(model.NewBoolVar(f'i{i}_j{j}'))
        x.append(t)


    # Constraints
    # Each item only assigned once to any store .
    [model.Add(sum(x[i][j] for j in all_shops) == 1) for i in all_items]

    
    
    
    # Adding the intermediate variable to constrain the number of the stores. 
    s=[]
    for j in all_shops:
        s.append( model.NewBoolVar(f's_{j}') )
      
    for j in all_shops:
        model.Add(sum(x[i][j] for i in all_items) >= 1).OnlyEnforceIf(s[j])
        model.Add(sum(x[i][j] for i in all_items) == 0).OnlyEnforceIf(s[j].Not())

    model.Add(sum(s[j] for j in all_shops) <= max_stops)

    
    
    
    # Create the Objective function Variable
    total_cost = model.NewIntvar(0,1000000,'total_cost')

    # Create the Objective function,Minimize (Sum of cost) 
    model.Add(total_cost == (sum(x[i][j] * cost[i][j] for j in all_shops for i in all_items )))


    model.Minimize(total_cost)

    

    #Initialize the Solver ... 
    solver = cp_model.cpsolver()

    status = solver.solve(model)

    
    print(solver.ResponseStats())
    Total_Cost,senario_cost = 0,0
    
    #printing the solution
    if status == cp_model.OPTIMAL:

        senario_cost={'Items':[],'Assigned_to':[],'Item_cost':[],'Num_stops':0,'cost':[]}
       
        Total_Cost = solver.ObjectiveValue()
        
        for i in range(num_items):
            for j in range(num_shops):
                if solver.Value(x[i][j]) == 1:
                    senario_cost['Items'].append(i)
                    senario_cost['Assigned_to'].append(j)
                    senario_cost['Item_cost'].append(cost[i][j])
        senario_cost['Num_stops'] = len(set(senario_cost['Assigned_to']))
        senario_cost['cost'] = cost
    
        return Total_Cost,senario_cost
    else:
        return None,None

我运行它时得到这个:

cpsolverResponse:
status: OPTIMAL
objective: 213
best_bound: 213
booleans: 210
conflicts: 106343
branches: 158796
propagations: 4242079
integer_propagations: 7844526
restarts: 878
lp_iterations: 0
walltime: 6.90529
usertime: 6.90529
deterministic_time: 4.67974
primal_integral: 0

cpu times: user 6.86 s,sys: 41 ms,total: 6.9 s
Wall time: 6.95 s

解决方法

当我在主分支上运行提供的代码时,没有并行性,我得到:

CpSolverResponse:
status: OPTIMAL
objective: 213
best_bound: 213
booleans: 210
conflicts: 31
branches: 617
propagations: 5226
integer_propagations: 8220
restarts: 428
lp_iterations: 130
walltime: 0.021303
usertime: 0.021303
deterministic_time: 0.0011162
primal_integral: 0.00536794

你得到不同的结果吗?