Integer Optimization(借助ortools)

注:中文非直接翻译英文,而是理解加工后的笔记,记录英文仅为学其专业表述。

Mixed-Integer Programming

变量部分(非全部)为整数的问题,可以用混合整数规划来解决Mixed Integer Programming (MIP)。MIP也可称为混合整数线性规划问题,Mixed Integer Linear Programming (MILP)。

MIP solvers

OR-Tools 提供多种MIP求解器,默认是开源求解器 Coin-or branch and cut (CBC)。如果从源码安装,可以使用其他第三方求解器如:

  • SCIP
  • GLPK
  • Gurobi

步骤:

  • 导入求解器
  • 声明求解器
  • 调用求解器

eg:

  • 目标: maximize(x + 10y)
  • 约束:
    • x + 7 y ≤ 17.5
    • x ≤ 3.5
    • x ≥ 0
    • y ≥ 0
    • x, y 都是整数
from ortools.linear_solver import pywraplp

def main():
    # Create the mip solver with the CBC backend.
    solver = pywraplp.Solver('simple_mip_program',
                             pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)

    infinity = solver.infinity()
    # x and y are integer non-negative variables.
    x = solver.IntVar(0.0, infinity, 'x')
    y = solver.IntVar(0.0, infinity, 'y')

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

    # x + 7 * y <= 17.5.
    solver.Add(x + 7 * y <= 17.5)

    # x <= 3.5.
    solver.Add(x <= 3.5)

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

    # Maximize x + 10 * y.
    solver.Maximize(x + 10 * y)

    result_status = solver.Solve()
    # The problem has an optimal solution.
    assert result_status == pywraplp.Solver.OPTIMAL

    # The solution looks legit (when using solvers others than
    # GLOP_LINEAR_PROGRAMMING, verifying the solution is highly recommended!).
    assert solver.VerifySolution(1e-7, True)

    print('Solution:')
    print('Objective value =', solver.Objective().Value())
    print('x =', x.solution_value())
    print('y =', y.solution_value())

    print('
Advanced usage:')
    print('Problem solved in %f milliseconds' % solver.wall_time())
    print('Problem solved in %d iterations' % solver.iterations())
    print('Problem solved in %d branch-and-bound nodes' % solver.nodes())


if __name__ == '__main__':
    main()

运行得

Number of variables = 2
Number of constraints = 2
Solution:
Objective value = 23.0
x = 3.0
y = 2.0

Advanced usage:
Problem solved in 28.000000 milliseconds
Problem solved in 1 iterations
Problem solved in 0 branch-and-bound nodes
  • solver.NumVar 实数变量
  • solver.IntVar 整数变量

对比线性和整数规划

猜测整数规划的解也许接近线性规划,但情况并非如此。

You might guess that the solution to the integer problem would be the integer point in the feasible region closest to the linear solution — namely, the point x = 0, y = 2. But as you will see next, this is not the case.

替换约束条件为

    infinity = solver.infinity()
    x = solver.NumVar(0, infinity, 'x')
    y = solver.NumVar(0, infinity, 'y')

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

运行得

Number of variables = 2
Number of variables = 2
Number of constraints = 2
Solution:
Objective value = 25.0
x = 0.0
y = 2.5

Advanced usage:
Problem solved in 20.000000 milliseconds
Problem solved in 0 iterations
Problem solved in 0 branch-and-bound nodes

CP Approach to Integer Optimization

约束优化(CP)不同于传统优化理论,它更关注约束和变量,而不是目标函数。有些问题,CP可以比MIP求解器更快地找到最优解。

  • 对于标准整数规划问题,可行点必须满足所有约束,MIP求解速度更快。在这种情况下,可行集是凸的:对于集合中的任意两点,连接它们的线段完全位于集合中。

  • 对于具有高度非凸可行集的问题,CP-SAT解算器通常比MIP解算器更快。当可行集由多个“或”连接的约束定义时,意味着一个点只需要满足其中一个约束即可。

eg: 转换非整数约束

为了提高计算速度,CP-SAT解算器和原始CP解算器都对整数进行运算。

To solve a problem in which some of the constraints have non-integer terms, you must first transform those constraints by multiplying them by a sufficiently large integer.

eg:

  • 目标: maximize(2x + 2y + 3z)
  • 约束:

egin{align} x+frac{7}{2}y+frac{3}{2}zleq25 \ 3x - 5y + 7z leq 45 \ 5x + 2y - 6z leq 37 \ x, y, z geq 0 \ x, y, z quad integers \ end{align}

用CP-SAT求解器来解

from ortools.sat.python import cp_model

def main():
  model = cp_model.CpModel()
  var_upper_bound = max(50, 45, 37)
  x = model.NewIntVar(0, var_upper_bound, 'x')
  y = model.NewIntVar(0, var_upper_bound, 'y')
  z = model.NewIntVar(0, var_upper_bound, 'z')

  model.Add(2*x + 7*y + 3*z <= 50)
  model.Add(3*x - 5*y + 7*z <= 45)
  model.Add(5*x + 2*y - 6*z <= 37)

  model.Maximize(2*x + 2*y + 3*z)

  solver = cp_model.CpSolver()
  status = solver.Solve(model)

  if status == cp_model.OPTIMAL:
    print('Maximum of objective function: %i' % solver.ObjectiveValue())
    print()
    print('x value: ', solver.Value(x))
    print('y value: ', solver.Value(y))
    print('z value: ', solver.Value(z))

if __name__ == '__main__':
  main()

运行得

Maximum of objective function: 35

x value:  7
y value:  3
z value:  5

用原始CP求解器来解

from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import solver_parameters_pb2

def main():
  # Instantiate a CP solver.
  parameters = pywrapcp.Solver.DefaultSolverParameters()
  solver = pywrapcp.Solver('simple_CP', parameters)
  var_upper_bound = max(50, 45, 37)
  x = solver.IntVar(0, var_upper_bound, 'x')
  y = solver.IntVar(0, var_upper_bound, 'y')
  z = solver.IntVar(0, var_upper_bound, 'z')
  solver.Add(2*x + 7*y + 3*z <= 50)
  solver.Add(3*x - 5*y + 7*z <= 45)
  solver.Add(5*x + 2*y - 6*z <= 37)
  objective = solver.Maximize(2*x + 2*y + 3*z, 1)
  decision_builder = solver.Phase([x, y, z],
                                  solver.CHOOSE_FIRST_UNBOUND,
                                  solver.ASSIGN_MAX_VALUE)
    # Create a solution collector.
  collector = solver.LastSolutionCollector()
  # Add the decision variables.
  collector.Add(x)
  collector.Add(y)
  collector.Add(z)
  # Add the objective.
  collector.AddObjective(2*x + 2*y +3*z)
  solver.Solve(decision_builder, [objective, collector])
  if collector.SolutionCount() > 0:
    best_solution = collector.SolutionCount() - 1
    print("Maximum of objective function:", collector.ObjectiveValue(best_solution))
    print()
    print('x= ', collector.Value(best_solution, x))
    print('y= ', collector.Value(best_solution, y))
    print('z= ', collector.Value(best_solution, z))

if __name__ == '__main__':
  main()

运行得

Maximum of objective function: 35

x=  7
y=  3
z=  5
原文地址:https://www.cnblogs.com/xrszff/p/10985749.html