Google 或工具中 MIP 程序的非最佳结果

Non-optimal result from MIP program in Google OR Tools

我正在研究一个示例 MIP 程序,一个男女混合运动队首发阵容的选择,并发现了一个在 Google OR 工具中得出非最佳结果的小例子。

基础知识:从 n>5 名球员中选择 5 名首发球员。至少有两名先发球员必须是女性。划伤玩家无法启动。 objective 函数是初学者技能水平的简单求和。代码是:

import pandas as pd
from ortools.linear_solver import pywraplp

# %% Read the data from an external file
pname   = ["Tom", "Joe", "Bill", "Mike", "Frank", "Mary", "Sue", "JoAnn"]
skill   = [ 11.0,  13.0,   11.0,   12.0,    14.0,   10.0,  10.0,     7.0]
female  = [    0,     0,      0,      0,       0,      1,     1,       1]
scratch = [    0,     0,      0,      0,       1,      0,     0,       0]

# %% Create the mip solver with the SCIP backend.
solver = pywraplp.Solver.CreateSolver('SCIP')

# %% Add the variables
starters = pd.Series([ solver.BoolVar(name = f'dv_{n}') for n in pname ])

# %% Add the objective function
solver.Maximize(solver.Sum(skill * starters))

# %% Add the constraints
solver.Add(solver.Sum(starters) == 5)
solver.Add(solver.Sum(starters * female) >= 2)
solver.Add(solver.Sum(starters * scratch) == 0)
#solver.Add(starters[3] == 1)

# %% Invoke the solver
status = solver.Solve()

# %% Report results
print("  START?   NAME PVAL     SEX SCRATCHED")
for i in (1,0) :
    for n in range(starters.count()) :
        if starters[n].SolutionValue() == i :
            print(
                f'{n} {"YES   " if i == 1 else "NO    "} {pname[n]:>6} {skill[n]:4.0f} ',
                f'{"female" if female[n] else "  male"} ',
                f'{"scratched" if scratch[n] else " - "}')
    print("---------------")
print(f'OBJECTIVE VALUE: {solver.Objective().Value()}')
# %%

objective 函数 returns 为 55,即使存在 56 的解。事实上,添加一个额外的约束(在上面的代码中注释掉)将产生最佳结果。 (Mike 可以代替 Bill 或 Tom 开始并且不违反任何约束。)

那么是什么原因呢?我做错了什么吗?为什么原始代码没有提供最优解?我使用的是正确的求解器吗??我很乐意认为这是我的模型规范中的一个问题,但如果是这样,我就无法理解它。

它适用于 CBCSAT,看来您必须为 SCIP 设置 PRIMAL_TOLERANCE

solver_parameters = pywraplp.MPSolverParameters()
solver_parameters.SetDoubleParam(pywraplp.MPSolverParameters.PRIMAL_TOLERANCE, 0.001)
status = solver.Solve(solver_parameters)