解决 LP 问题

以下部分展示了一个 LP 问题示例,并展示如何解决该问题。问题如下:

尽可能增加 3x + 4y,但需遵循以下限制条件

  1. x + 2y ≤ 14
  2. 3x - y ≥ 0
  3. x - y ≤ 2

目标函数 3x + 4y 和约束条件均由线性表达式给出,这使得此问题成为线性问题。

这些约束条件定义了可行区域,即下方显示的三角形,包括其内部。

解决 LP 问题的基本步骤

要解决 LP 问题,您的程序应包含以下步骤:

  1. 导入线性求解器封装容器,
  2. 声明 LP 求解器,
  3. 定义变量
  4. 定义约束条件,
  5. 定义目标,
  6. 调用 LP 求解器;
  7. 展示解决方案

使用 MPSolver 的解决方案

以下部分展示了一个使用 MPSolver 封装容器和 LP 求解器来解决问题的程序。

注意:如需运行以下程序,您需要安装 OR-Tools

主要的 OR-Tools 线性优化求解器是 Glop,这是 Google 的内部线性编程求解器。它运行速度快、内存高效且数值稳定。

导入线性求解器封装容器

导入(或包含)OR-Tools 线性求解器封装容器(MIP 求解器和线性求解器的接口),如下所示。

from ortools.linear_solver import pywraplp
#include <iostream>
#include <memory>

#include "ortools/linear_solver/linear_solver.h"
import com.google.ortools.Loader;
import com.google.ortools.linearsolver.MPConstraint;
import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;
using System;
using Google.OrTools.LinearSolver;

声明 LP 求解器

MPsolver 是多个不同求解器(包括 Glop)的封装容器。以下代码声明了 GLOP 求解器。

solver = pywraplp.Solver.CreateSolver("GLOP")
if not solver:
   
return
std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP"));
if (!solver) {
  LOG
(WARNING) << "SCIP solver unavailable.";
 
return;
}
MPSolver solver = MPSolver.createSolver("GLOP");
Solver solver = Solver.CreateSolver("GLOP");
if (solver is null)
{
   
return;
}

注意:将 GLOP 替换为 PDLP 以使用替代 LP 求解器。如需详细了解如何选择求解器,请参阅高级 LP 求解器;如需了解如何安装第三方求解器,请参阅安装指南

创建变量

首先,创建变量 x 和 y,它们的值介于 0 到无穷大之间。xx

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

print("Number of variables =", solver.NumVariables())
const double infinity = solver->infinity();
// x and y are non-negative variables.
MPVariable* const x = solver->MakeNumVar(0.0, infinity, "x");
MPVariable* const y = solver->MakeNumVar(0.0, infinity, "y");
LOG
(INFO) << "Number of variables = " << solver->NumVariables();
double infinity = java.lang.Double.POSITIVE_INFINITY;
// x and y are continuous non-negative variables.
MPVariable x = solver.makeNumVar(0.0, infinity, "x");
MPVariable y = solver.makeNumVar(0.0, infinity, "y");
System.out.println("Number of variables = " + solver.numVariables());
Variable x = solver.MakeNumVar(0.0, double.PositiveInfinity, "x");
Variable y = solver.MakeNumVar(0.0, double.PositiveInfinity, "y");

Console.WriteLine("Number of variables = " + solver.NumVariables());

定义限制条件

接下来,定义对变量的约束条件。为每个约束条件指定一个唯一的名称(例如 constraint0),然后定义该约束条件的系数。

# Constraint 0: x + 2y <= 14.
solver
.Add(x + 2 * y <= 14.0)

# Constraint 1: 3x - y >= 0.
solver
.Add(3 * x - y >= 0.0)

# Constraint 2: x - y <= 2.
solver
.Add(x - y <= 2.0)

print("Number of constraints =", solver.NumConstraints())
// x + 2*y <= 14.
MPConstraint* const c0 = solver->MakeRowConstraint(-infinity, 14.0);
c0
->SetCoefficient(x, 1);
c0
->SetCoefficient(y, 2);

// 3*x - y >= 0.
MPConstraint* const c1 = solver->MakeRowConstraint(0.0, infinity);
c1
->SetCoefficient(x, 3);
c1
->SetCoefficient(y, -1);

// x - y <= 2.
MPConstraint* const c2 = solver->MakeRowConstraint(-infinity, 2.0);
c2
->SetCoefficient(x, 1);
c2
->SetCoefficient(y, -1);
LOG
(INFO) << "Number of constraints = " << solver->NumConstraints();
// x + 2*y <= 14.
MPConstraint c0 = solver.makeConstraint(-infinity, 14.0, "c0");
c0
.setCoefficient(x, 1);
c0
.setCoefficient(y, 2);

// 3*x - y >= 0.
MPConstraint c1 = solver.makeConstraint(0.0, infinity, "c1");
c1
.setCoefficient(x, 3);
c1
.setCoefficient(y, -1);

// x - y <= 2.
MPConstraint c2 = solver.makeConstraint(-infinity, 2.0, "c2");
c2
.setCoefficient(x, 1);
c2
.setCoefficient(y, -1);
System.out.println("Number of constraints = " + solver.numConstraints());
// x + 2y <= 14.
solver
.Add(x + 2 * y <= 14.0);

// 3x - y >= 0.
solver
.Add(3 * x - y >= 0.0);

// x - y <= 2.
solver
.Add(x - y <= 2.0);

Console.WriteLine("Number of constraints = " + solver.NumConstraints());

定义目标函数

以下代码定义了目标函数 3x + 4y,并指定这是一个最大化问题。

# Objective function: 3x + 4y.
solver
.Maximize(3 * x + 4 * y)
// Objective function: 3x + 4y.
MPObjective* const objective = solver->MutableObjective();
objective
->SetCoefficient(x, 3);
objective
->SetCoefficient(y, 4);
objective
->SetMaximization();
// Maximize 3 * x + 4 * y.
MPObjective objective = solver.objective();
objective
.setCoefficient(x, 3);
objective
.setCoefficient(y, 4);
objective
.setMaximization();
// Objective function: 3x + 4y.
solver
.Maximize(3 * x + 4 * y);

调用求解器

以下代码会调用求解器。

print(f"Solving with {solver.SolverVersion()}")
status
= solver.Solve()
const MPSolver::ResultStatus result_status = solver->Solve();
// Check that the problem has an optimal solution.
if (result_status != MPSolver::OPTIMAL) {
  LOG
(FATAL) << "The problem does not have an optimal solution!";
}
final MPSolver.ResultStatus resultStatus = solver.solve();
Solver.ResultStatus resultStatus = solver.Solve();

显示解决方案

以下代码将显示解决方案。

if status == pywraplp.Solver.OPTIMAL:
   
print("Solution:")
   
print(f"Objective value = {solver.Objective().Value():0.1f}")
   
print(f"x = {x.solution_value():0.1f}")
   
print(f"y = {y.solution_value():0.1f}")
else:
   
print("The problem does not have an optimal solution.")
LOG(INFO) << "Solution:";
LOG
(INFO) << "Optimal objective value = " << objective->Value();
LOG
(INFO) << x->name() << " = " << x->solution_value();
LOG
(INFO) << y->name() << " = " << y->solution_value();
if (resultStatus == MPSolver.ResultStatus.OPTIMAL) {
 
System.out.println("Solution:");
 
System.out.println("Objective value = " + objective.value());
 
System.out.println("x = " + x.solutionValue());
 
System.out.println("y = " + y.solutionValue());
} else {
 
System.err.println("The problem does not have an optimal solution!");
}
// Check that the problem has an optimal solution.
if (resultStatus != Solver.ResultStatus.OPTIMAL)
{
   
Console.WriteLine("The problem does not have an optimal solution!");
   
return;
}
Console.WriteLine("Solution:");
Console.WriteLine("Objective value = " + solver.Objective().Value());
Console.WriteLine("x = " + x.SolutionValue());
Console.WriteLine("y = " + y.SolutionValue());

完整的计划

完整的程序如下所示。

from ortools.linear_solver import pywraplp


def LinearProgrammingExample():
   
"""Linear programming sample."""
   
# Instantiate a Glop solver, naming it LinearExample.
    solver
= pywraplp.Solver.CreateSolver("GLOP")
   
if not solver:
       
return

   
# Create the two variables and let them take on any non-negative value.
    x
= solver.NumVar(0, solver.infinity(), "x")
    y
= solver.NumVar(0, solver.infinity(), "y")

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

   
# Constraint 0: x + 2y <= 14.
    solver
.Add(x + 2 * y <= 14.0)

   
# Constraint 1: 3x - y >= 0.
    solver
.Add(3 * x - y >= 0.0)

   
# Constraint 2: x - y <= 2.
    solver
.Add(x - y <= 2.0)

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

   
# Objective function: 3x + 4y.
    solver
.Maximize(3 * x + 4 * y)

   
# Solve the system.
   
print(f"Solving with {solver.SolverVersion()}")
    status
= solver.Solve()

   
if status == pywraplp.Solver.OPTIMAL:
       
print("Solution:")
       
print(f"Objective value = {solver.Objective().Value():0.1f}")
       
print(f"x = {x.solution_value():0.1f}")
       
print(f"y = {y.solution_value():0.1f}")
   
else:
       
print("The problem does not have an optimal solution.")

   
print("\nAdvanced usage:")
   
print(f"Problem solved in {solver.wall_time():d} milliseconds")
   
print(f"Problem solved in {solver.iterations():d} iterations")


LinearProgrammingExample()
#include <iostream>
#include <memory>

#include "ortools/linear_solver/linear_solver.h"

namespace operations_research {
void LinearProgrammingExample() {
  std
::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP"));
 
if (!solver) {
    LOG
(WARNING) << "SCIP solver unavailable.";
   
return;
 
}

 
const double infinity = solver->infinity();
 
// x and y are non-negative variables.
 
MPVariable* const x = solver->MakeNumVar(0.0, infinity, "x");
 
MPVariable* const y = solver->MakeNumVar(0.0, infinity, "y");
  LOG
(INFO) << "Number of variables = " << solver->NumVariables();

 
// x + 2*y <= 14.
 
MPConstraint* const c0 = solver->MakeRowConstraint(-infinity, 14.0);
  c0
->SetCoefficient(x, 1);
  c0
->SetCoefficient(y, 2);

 
// 3*x - y >= 0.
 
MPConstraint* const c1 = solver->MakeRowConstraint(0.0, infinity);
  c1
->SetCoefficient(x, 3);
  c1
->SetCoefficient(y, -1);

 
// x - y <= 2.
 
MPConstraint* const c2 = solver->MakeRowConstraint(-infinity, 2.0);
  c2
->SetCoefficient(x, 1);
  c2
->SetCoefficient(y, -1);
  LOG
(INFO) << "Number of constraints = " << solver->NumConstraints();

 
// Objective function: 3x + 4y.
 
MPObjective* const objective = solver->MutableObjective();
  objective
->SetCoefficient(x, 3);
  objective
->SetCoefficient(y, 4);
  objective
->SetMaximization();

 
const MPSolver::ResultStatus result_status = solver->Solve();
 
// Check that the problem has an optimal solution.
 
if (result_status != MPSolver::OPTIMAL) {
    LOG
(FATAL) << "The problem does not have an optimal solution!";
 
}

  LOG
(INFO) << "Solution:";
  LOG
(INFO) << "Optimal objective value = " << objective->Value();
  LOG
(INFO) << x->name() << " = " << x->solution_value();
  LOG
(INFO) << y->name() << " = " << y->solution_value();
}
}  // namespace operations_research

int main(int argc, char** argv) {
  operations_research
::LinearProgrammingExample();
 
return EXIT_SUCCESS;
}
package com.google.ortools.linearsolver.samples;
import com.google.ortools.Loader;
import com.google.ortools.linearsolver.MPConstraint;
import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;

/** Simple linear programming example. */
public final class LinearProgrammingExample {
 
public static void main(String[] args) {
   
Loader.loadNativeLibraries();
   
MPSolver solver = MPSolver.createSolver("GLOP");

   
double infinity = java.lang.Double.POSITIVE_INFINITY;
   
// x and y are continuous non-negative variables.
   
MPVariable x = solver.makeNumVar(0.0, infinity, "x");
   
MPVariable y = solver.makeNumVar(0.0, infinity, "y");
   
System.out.println("Number of variables = " + solver.numVariables());

   
// x + 2*y <= 14.
   
MPConstraint c0 = solver.makeConstraint(-infinity, 14.0, "c0");
    c0
.setCoefficient(x, 1);
    c0
.setCoefficient(y, 2);

   
// 3*x - y >= 0.
   
MPConstraint c1 = solver.makeConstraint(0.0, infinity, "c1");
    c1
.setCoefficient(x, 3);
    c1
.setCoefficient(y, -1);

   
// x - y <= 2.
   
MPConstraint c2 = solver.makeConstraint(-infinity, 2.0, "c2");
    c2
.setCoefficient(x, 1);
    c2
.setCoefficient(y, -1);
   
System.out.println("Number of constraints = " + solver.numConstraints());

   
// Maximize 3 * x + 4 * y.
   
MPObjective objective = solver.objective();
    objective
.setCoefficient(x, 3);
    objective
.setCoefficient(y, 4);
    objective
.setMaximization();

   
final MPSolver.ResultStatus resultStatus = solver.solve();

   
if (resultStatus == MPSolver.ResultStatus.OPTIMAL) {
     
System.out.println("Solution:");
     
System.out.println("Objective value = " + objective.value());
     
System.out.println("x = " + x.solutionValue());
     
System.out.println("y = " + y.solutionValue());
   
} else {
     
System.err.println("The problem does not have an optimal solution!");
   
}

   
System.out.println("\nAdvanced usage:");
   
System.out.println("Problem solved in " + solver.wallTime() + " milliseconds");
   
System.out.println("Problem solved in " + solver.iterations() + " iterations");
 
}

 
private LinearProgrammingExample() {}
}
using System;
using Google.OrTools.LinearSolver;

public class LinearProgrammingExample
{
   
static void Main()
   
{
       
Solver solver = Solver.CreateSolver("GLOP");
       
if (solver is null)
       
{
           
return;
       
}
       
// x and y are continuous non-negative variables.
       
Variable x = solver.MakeNumVar(0.0, double.PositiveInfinity, "x");
       
Variable y = solver.MakeNumVar(0.0, double.PositiveInfinity, "y");

       
Console.WriteLine("Number of variables = " + solver.NumVariables());

       
// x + 2y <= 14.
        solver
.Add(x + 2 * y <= 14.0);

       
// 3x - y >= 0.
        solver
.Add(3 * x - y >= 0.0);

       
// x - y <= 2.
        solver
.Add(x - y <= 2.0);

       
Console.WriteLine("Number of constraints = " + solver.NumConstraints());

       
// Objective function: 3x + 4y.
        solver
.Maximize(3 * x + 4 * y);

       
Solver.ResultStatus resultStatus = solver.Solve();

       
// Check that the problem has an optimal solution.
       
if (resultStatus != Solver.ResultStatus.OPTIMAL)
       
{
           
Console.WriteLine("The problem does not have an optimal solution!");
           
return;
       
}
       
Console.WriteLine("Solution:");
       
Console.WriteLine("Objective value = " + solver.Objective().Value());
       
Console.WriteLine("x = " + x.SolutionValue());
       
Console.WriteLine("y = " + y.SolutionValue());

       
Console.WriteLine("\nAdvanced usage:");
       
Console.WriteLine("Problem solved in " + solver.WallTime() + " milliseconds");
       
Console.WriteLine("Problem solved in " + solver.Iterations() + " iterations");
   
}
}

最佳解决方案

程序会返回问题的最佳解决方案,如下所示。

Number of variables = 2
Number of constraints = 3
Solution:
x = 6.0
y = 4.0
Optimal objective value = 34.0

下图显示了该解决方案:

绿色虚线通过将目标函数设置为等于其最佳值 34 来定义。任何方程式为 3x + 4y = c 的直线都平行于虚线,且 34 是该直线与可行区域相交的 c 的最大值。

如需详细了解如何解决线性优化问题,请参阅高级 LP 求解