如何在Google OR-Tools中实现高精度资源分配误差最小化模型
问题定义
我需要对资源进行分组,让每组的平均价格尽可能接近给定的目标平均价格。输入是包含价格和数量的资源列表,以及目标分组的数量和平均价格,最终要把资源数量分配到各组,使每组实际平均价格与目标价格的偏差最小。
我将这个问题建模为误差最小化问题,约束条件包括:
- 所有资源数量必须被完全分配
- 资源总数量 = 目标分组总数量
我已经用Choco Solver实现了该模型,但它使用integer类型存储变量,无法满足实际场景的精度需求(实际价格含小数,需缩放为整数处理)。现在我想把模型迁移到支持long类型的Google OR-Tools以提升精度,但不知道如何在OR-Tools的API中定义需要最小化的误差函数,求相关实现经验。
模型定义
R = 输入资源集合, G = 输出分组集合, Rq = 资源数量, Rp = 资源价格, Gq = 分组目标数量, Gp = 分组目标平均价格
待计算变量:分配给分组j的资源i的数量RiGj
约束条件
// 每组分配到的资源数量总和等于该组的目标数量 Gjq = SUM(RiGj) // 每个资源分配出去的数量总和等于该资源的可用数量 Riq = SUM(RiGj) // 每组的价格偏差计算 Ej = ABS(SUM(RiGj * Rip)/Gjq - Gjp)
求解目标:最小化所有分组的偏差总和SUM(Ej)
可运行的Choco解决方案
Model model = new Model(); IntVar[] vars = new IntVar[resources.length * groups.length]; ArExpression[] groupQtyConstraint = new ArExpression[groups.length]; ArExpression[] resourceQtyConstraint = new ArExpression[resources.length]; ArExpression[] error = new ArExpression[groups.length]; for (int i = 0; i < groups.length; i++) { for (int j = 0; j < resources.length; j++) { // 变量定义 IntVar curr = model.intVar(0, resources[j].quantity().intValue()); vars[i * resources.length + j] = curr; // 构建分组数量约束 if (groupQtyConstraint[i] == null) { groupQtyConstraint[i] = curr; } else { groupQtyConstraint[i] = groupQtyConstraint[i].add(curr); } // 构建资源数量约束 if (resourceQtyConstraint[j] == null) { resourceQtyConstraint[j] = curr; } else { resourceQtyConstraint[j] = resourceQtyConstraint[j].add(curr); } // 构建平均价格计算逻辑 // TODO: 此处存在精度问题 - int类型精度不足 if (error[i] == null) { error[i] = curr.mul(resources[j].price()); } else { error[i] = error[i].add(curr.mul(resources[j].price())); } } model.arithm(groupQtyConstraint[i].intVar(), "=", groups[i].quantity()).post(); } for (int i = 0; i < resources.length; i++) { model.arithm(resourceQtyConstraint[i].intVar(), "=", resources[i].quantity()).post(); } ArExpression objective = null; for (int i = 0; i < groups.length; i++) { error[i] = error[i] .div(groups[i].quantity()) .sub(groups[i].price()) .abs(); if (objective == null) { objective = error[i]; } else { objective = objective.add(error[i]); } } // 寻找最小化误差的最优解 Solver solver = model.getSolver(); Solution optimalSolution = solver.findOptimalSolution(objective.intVar(), Model.MINIMIZE);
示例
输入
资源列表: [ ("R1", 12, 103.5), ("R2", 6, 102.45), ("R3", 2, 100.10) ] 分组列表: [ ("G1", 6, 102.5833), ("G2", 14, 102.9571) ]
最优解
"G1": [ ("R1", 3), ("R2", 2), ("R3", 1) ] "G2": [ ("R1", 9), ("R2", 4), ("R3", 1) ]
注:本示例中已将价格乘以10000转换为整数处理。
核心疑问
我无法理清如何在OR-Tools中定义并最小化如下误差函数:Ej = ABS(SUM(RiGj * Rip)/Gjq - Gjp)
内容的提问来源于stack exchange,提问作者Marcelo Grossi
相关产品推荐
相关产品推荐

