ortools / 线性规划 - 最小化跨供应商的购物篮成本

问题描述

作为约束编程和 ORTools 的新手,我不确定如何采取下一步来解决这个问题..

这是经典的“最小化多个供应商之间的购物车成本”(抱歉!!)

我有 python/ORTools 计算整个篮子的最低成本(在可能的情况下),使用变量矩阵 - 项目与从每个供应商订购的数量 - 但我想将以下内容添加到模型中:

  1. 运输成本(每个供应商可能会有所不同,以及来自该供应商的商品数量(例如: 供应商 1:5 件商品 = 2 美元运费 供应商 2:5 件商品 = 免运费
  2. 商店信用 - 如果我有商店信用,我想将其考虑在内 - 优先使用商店信用

如果找不到完整的篮子(例如,我想要 10 件商品,但所有供应商只有 5 件有存货,是否有可能获得最接近的解决方案?(最接近的最低价格是最多数量的想要商品?) ) - 目前它只是说没有找到解决方案。(更改第 18 行 - items[0] = 10 以触发)

很高兴去挖掘,但不确定要寻找什么!谢谢!!

代码如下:

from ortools.linear_solver import pywraplp

#prices at vendors of each item
#(eg item 2 is 0.05 at vendor 2)
allStockPrice = {}
allStockPrice[0] = [10,11]
allStockPrice[1] = [0.15,0.20]
allStockPrice[2] = [0.04,0.05]

#stock at vendors of each item
allStockQty = {}
allStockQty[0] = [1,6]
allStockQty[1] = [0,2]
allStockQty[2] = [5,1]

#number of each item that I want to purchase
items = {}
items[0] = 5
items[1] = 2
items[2] = 1

#create a variable array for the solver
#how many of each item am I ordering from each vendor?
variable_list = [[]] * len(items)
variable_list[0] = [[]] * len(allStockPrice[0])
variable_list[1] = [[]] * len(allStockPrice[0])
variable_list[2] = [[]] * len(allStockPrice[0])

def configure_objective(solver):
    global allStockPrice,variable_list

    objective = solver.Objective()

    #coefficient for each variable is the cost to purchase
    for i in items:
        for j in range(len(allStockPrice[0])):
            objective.SetCoefficient(variable_list[i][j],allStockPrice[i][j])

    objective.SetMinimization()

    return objective

def configure_constraints(solver):
    global allStockPrice,allStockQty,items,variable_list

    #can only have upto the maximum amount wanted of each item
    for i in items:
        solver.Add(sum(variable_list[i]) == items[i])

    #items must be in stock at the vendor
    for i in items:
        for j in range(len(allStockPrice[0])):
            solver.Add(variable_list[i][j] <= allStockQty[i][j])

def configure_variables(solver):
    global allStockPrice,items

    #must get between 0 and x items
    for i in items:
        for j in range(len(allStockPrice[0])):
            variable_list[i][j] = solver.Intvar(0,items[i],str('x_i%i_v%i' % (i,j)))

    return variable_list

def solve(solver):
    result_status = solver.solve()
    return result_status


def print_solution(solver,result_status,variable_list,constraint_list):
    if result_status == solver.OPTIMAL:
        print('Successful solve.')
        # The problem has an optimal solution.
        print(('Problem solved in %f milliseconds' % solver.wall_time()))
        # The objective value of the solution.
        print(('Optimal objective value = %f' % solver.Objective().Value()))
        # The value of each variable in the solution.
        var_sum = 0

        print (variable_list)
        for variable in variable_list:
            for vendor in variable:
                print(('%s = %f' % (vendor.name(),vendor.solution_value())))
                var_sum += vendor.solution_value()
        print(('Variable sum = %f' % var_sum));

        print('Advanced usage:')
        print(('Problem solved in %d iterations' % solver.iterations()))

        for variable in variable_list:
            for vendor in variable:
                print(('%s: reduced cost = %f' % (vendor.name(),vendor.reduced_cost())))

    elif result_status == solver.INFEASIBLE:
        print('No solution found.')
    elif result_status == solver.POSSIBLE_OVERFLOW:
        print('Some inputs are too large and may cause an integer overflow.')

solver = pywraplp.solver('SolveSimpleSystem',pywraplp.solver.GLOP_LINEAR_PROGRAMMING)

variable_list = configure_variables(solver)
constraint_list = configure_constraints(solver)
objective = configure_objective(solver)

result_status = solve(solver)

print_solution(solver,None)

解决方法

尝试手动创建解决方案,您会发现没有解决方案。

sum(variable_list[i]) == items[i] with i = 0 是不可能满足的,您总共有 7 件库存,但您迫使求解器购买 10 件。

如果您想找到“最接近”的解决方案,您需要通过使用“软约束”来定义一个最接近可行解决方案是最优的优化问题。在您的示例中,最简单的方法是定义一个具有无限库存和非常昂贵的物品的假第三供应商。仅当其中一个常规供应商无法满足需求时才会使用此方法。

https://colab.research.google.com/drive/1nBrMsUxCVea5PG8juzfdYPm4PdM6N9dJ?usp=sharing