You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Excel Solver与Python版OR-Tools求解器结果差异原因排查

问题

使用OR-Tools 9.9.3963的CLP求解器实现线性规划模型,发现与Excel Solver的求解结果存在1的差异:Excel Solver结果为1,191,892,387,OR-Tools结果为1,191,892,386。Python代码如下:

from ortools.linear_solver import pywraplp

def LinearProgrammingExample():
    # 初始化求解器
    solver = pywraplp.Solver.CreateSolver('CLP')

    # 创建变量x1到x31
    infinity = solver.infinity()
    for x in range(1, 32):
        globals()[f"x{x}"] = solver.NumVar(0.0, infinity, f"x{x}")

    print('Number of variables =', solver.NumVariables())

    # 定义约束相关的分组变量
    l1  =  sum([x1,x8,x15,x22,x29,x30])
    l1_dl  =  sum([x1,x8,x15,x22])
    l1_bds  =  sum([x8])
    l1_hq  =  sum([x29,x30])

    l2  =  sum([x2,x9,x16,x23])
    l2_dl  =  sum([x2,x9,x16,x23])
    l2_bds  =  sum([x9])

    l3  =  sum([x3,x10,x17,x24])
    l3_dl  =  sum([x3,x10,x17,x24])
    l3_bds  =  sum([x10])

    l4_2  =  sum([x4,x11,x18,x25])
    l4_2_dl  =  sum([x4,x11,x18,x25])
    l4_2_bds  =  sum([x11])
    
    l4_3  =  sum([x5,x12,x19,x26])
    l4_3_dl  =  sum([x5,x12,x19,x26])
    l4_3_bds  =  sum([x12])

    l5  =  sum([x6,x13,x20,x27])
    l5_dl  =  sum([x6,x13,x20,x27])
    l5_bds  =  sum([x13])

    l6  =  sum([x7,x14,x21,x28])
    l6_dl  =  sum([x7,x15,x23,x30])
    l6_bds  =  sum([x14])

    # 定义资产分配分组
    c1  =  sum([x1,x2,x3,x4,x5,x6,x7])
    c2  =  sum([x8,x9,x10,x11,x12,x13,x14])
    c3  =  sum([x15,x16,x17,x18,x19,x20,x21])
    c4  =  sum([x22,x23,x24,x25,x26,x27,x28])
    c5  =  sum([x29])
    c6  =  sum([x30])

    # 参数定义
    pC11 = 0
    pJ3 = 0.5
    pK3 = 0
    pN3 = 0.5
    pM3 = 0
    pL3 = 0.5
    pAe3 = 0
    pAe4 = 0
    pAe5 = 0
    pAe6 = 0
    pAe7 = 0
    pAe8 =  0  
    pAe9 = 0
    pAe10 = 0
    pAe11 = 0

    # 添加约束
    solver.Add(c1 <= 2303087800) # c1
    solver.Add(c2 <= 0) # c2
    solver.Add(c3 <= 0) # c3
    solver.Add(c4 <= 0) # c4
    solver.Add(c5 <= 0) # c5
    solver.Add(c6 <= 0) # c6

    solver.Add(x31 <= 3585716787) # c7
    solver.Add(x31 <= 3585716787) # c8

    solver.Add(l1_dl - x31 *(pJ3-pC11) >= 1707141607) # c9
    solver.Add(l2_dl >= 0) # c10
    solver.Add(l3_dl >= 0) # c11
    solver.Add(l4_2_dl >= 0) # c12
    solver.Add(l4_3_dl >= 0) # c13
    solver.Add(l5_dl >= 0) # c14
    solver.Add(l6_dl >= 0) # c15

    solver.Add(l1_bds - x31* pK3 >= 0) # c16
    solver.Add(l2_bds >= 0) # c17
    solver.Add(l3_bds >= 0) # c18
    solver.Add(l4_2_bds >= 0) # c19
    solver.Add(l4_3_bds >= 0) # c20
    solver.Add(l5_bds >= 0) # c21
    solver.Add(l6_bds >= 0) # c22 

    solver.Add(l1_dl + pAe3 - x31*(1-pL3-pC11) >= 1707141607) #c23

    solver.Add(l2_dl + pAe4 >= 0) # c24
    solver.Add(l3_dl + pAe5 >= 0) # c25
    solver.Add(l4_2_dl + pAe8 >= 0) # c26
    solver.Add(l4_3_dl + pAe9 >= 0) # c27
    solver.Add(l5_dl + pAe10 >= 0) # c28
    solver.Add(l6_dl + pAe11 >= 0) # c29

    solver.Add(l1_hq - x31* pM3 <= 0) # c30

    solver.Add(l1 + pAe3 -(1-pN3-pC11)*x31 >= 1707141607) # c31
    solver.Add(l2 + pAe4 >= 0) # c32
    solver.Add(l3 + pAe5 >= 0) # c33
    solver.Add(l4_2 + pAe8 >= 0) # c34
    solver.Add(l4_3 + pAe9 >= 0) # c35
    solver.Add(l5 + pAe10 >= 0) # c36
    solver.Add(l6 + pAe11 >= 0) # c37

    for x in range(1, 32):
        solver.Add(globals()[f"x{x}"] >= 0)

    print('Number of constraints =', solver.NumConstraints())

    # 设置目标函数:最大化x31
    solver.Maximize(x31)

    # 求解模型
    status = solver.Solve()

    # 输出结果
    if status == pywraplp.Solver.OPTIMAL:
        print('Solution:')
        for v in solver.variables():
            print(v, "=", v.solution_value())
        print('Objective value =', solver.Objective().Value())
    else:
        print('The problem does not have an optimal solution.')

    # 输出求解信息
    print('\nAdvanced usage:')
    print('Problem solved in %f milliseconds' % solver.wall_time())
    print('Problem solved in %d iterations' % solver.iterations())

LinearProgrammingExample()

差异原因分析

1. 模型定义存在笔误(最可能原因)

观察Python代码中l6_dl的定义:

l6_dl = sum([x7,x15,x23,x30])

而对应的l6分组是sum([x7,x14,x21,x28]),对比其他l*_dl的定义(比如l1_dl是l1的前4个变量),这里明显错误引用了不属于l6组的变量(x15、x23、x30)。如果Excel中的模型正确定义了l6_dl为x7,x14,x21,x28,两个模型的约束条件会完全不同,直接导致求解结果差异。

2. 浮点数计算精度与舍入差异

问题中的数值规模达到十亿级别,CLP和Excel Solver的浮点数计算逻辑、舍入策略不同:

  • 即使模型完全一致,大规模数值下的微小精度误差可能被放大,导致最终整数结果差1。比如OR-Tools求解得到的x31可能是1191892386.9999999,显示时被截断为整数;而Excel Solver可能自动舍入为1191892387。
  • 两个求解器采用的双精度浮点数迭代精度不同,CLP的默认计算精度可能更严格,导致结果更接近真实浮点值,而Excel可能有更宽松的精度处理。

3. 求解器终止容差设置不同

不同求解器的默认最优性容差和可行性容差存在差异:

  • Excel Solver的默认容差可能更宽松,允许约束存在微小的违反,从而得到更大的x31值。
  • OR-Tools的CLP默认容差更严格,确保解严格满足所有约束,因此得到的x31比Excel小1。

4. 变量类型约束差异

检查Excel模型是否将x31设置为整数变量:

  • 如果Excel强制x31为整数,而Python代码中x31是连续数值变量(NumVar),OR-Tools求解的是连续线性规划,结果可能是浮点值,显示时被截断为整数;而Excel直接求解整数规划,得到整数结果。

内容的提问来源于stack exchange,提问作者Zizi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:30:54