In den folgenden Abschnitten wird ein Beispiel für ein MIP-Problem mit entsprechenden Lösungsvorschlägen beschrieben. Hier ist das Problem:
Die x + 10y
-Maximierung unterliegt den folgenden Einschränkungen:
x + 7y
≤ 17,5- 0 ≤
x
≤ 3,5 - 0 ≤
y
x
,y
Ganzzahlen
Da die Einschränkungen linear sind, ist dies nur ein lineares Optimierungsproblem, bei dem die Lösungen Ganzzahlen sein müssen. Das folgende Diagramm zeigt die Ganzzahlpunkte in dem zulässigen Bereich für das Problem.
Beachten Sie, dass dieses Problem dem linearen Optimierungsproblem, das unter Ein LP-Problem lösen beschrieben ist, sehr ähnlich ist. In diesem Fall müssen die Lösungen jedoch Ganzzahlen sein.
Grundlegende Schritte zur Lösung eines MIP-Problems
Zur Lösung eines MIP-Problems sollte Ihr Programm die folgenden Schritte enthalten:
- Importieren Sie den Wrapper für den Linear Solver
- den MIP-Rechner,
- die Variablen definieren,
- die Einschränkungen zu definieren,
- das Ziel zu definieren,
- rufen Sie den MIP Solver auf
- Lösung anzeigen
Lösung mit MPsolver
Im folgenden Abschnitt wird ein Programm vorgestellt, das das Problem mithilfe des Wrappers MPSolver und eines MIP-Behebers löst.
Der Standard-MIP-Resolver „OR-Tools“ ist SCIP.
Lineare Solver-Wrapper importieren
Importieren (oder schließen) Sie den Linear Solver-Wrapper der OR-Tools, eine Schnittstelle für MIP-Resolver und Linear Solver, wie unten dargestellt.
Python
from ortools.linear_solver import pywraplp
C++
#include <memory> #include "ortools/linear_solver/linear_solver.h"
Java
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;
C#
using System; using Google.OrTools.LinearSolver;
MIP-Rechner deklarieren
Mit dem folgenden Code wird der MIP-Rechner für das Problem deklariert. In diesem Beispiel wird der Drittanbieter-Soller SCIP verwendet.
Python
# Create the mip solver with the SCIP backend. solver = pywraplp.Solver.CreateSolver("SAT") if not solver: return
C++
// Create the mip solver with the SCIP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP")); if (!solver) { LOG(WARNING) << "SCIP solver unavailable."; return; }
Java
// Create the linear solver with the SCIP backend. MPSolver solver = MPSolver.createSolver("SCIP"); if (solver == null) { System.out.println("Could not create solver SCIP"); return; }
C#
// Create the linear solver with the SCIP backend. Solver solver = Solver.CreateSolver("SCIP"); if (solver is null) { return; }
Variablen definieren
Der folgende Code definiert die Variablen in der Aufgabe.
Python
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())
C++
const double infinity = solver->infinity(); // x and y are integer non-negative variables. MPVariable* const x = solver->MakeIntVar(0.0, infinity, "x"); MPVariable* const y = solver->MakeIntVar(0.0, infinity, "y"); LOG(INFO) << "Number of variables = " << solver->NumVariables();
Java
double infinity = java.lang.Double.POSITIVE_INFINITY; // x and y are integer non-negative variables. MPVariable x = solver.makeIntVar(0.0, infinity, "x"); MPVariable y = solver.makeIntVar(0.0, infinity, "y"); System.out.println("Number of variables = " + solver.numVariables());
C#
// x and y are integer non-negative variables. Variable x = solver.MakeIntVar(0.0, double.PositiveInfinity, "x"); Variable y = solver.MakeIntVar(0.0, double.PositiveInfinity, "y"); Console.WriteLine("Number of variables = " + solver.NumVariables());
Das Programm verwendet die Methode MakeIntVar
(oder eine Variante, je nach Programmiersprache), um die Variablen x
und y
zu erstellen, die nicht negative Ganzzahlwerte annehmen.
Einschränkungen definieren
Der folgende Code definiert die Einschränkungen für das Problem.
Python
# 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())
C++
// x + 7 * y <= 17.5. MPConstraint* const c0 = solver->MakeRowConstraint(-infinity, 17.5, "c0"); c0->SetCoefficient(x, 1); c0->SetCoefficient(y, 7); // x <= 3.5. MPConstraint* const c1 = solver->MakeRowConstraint(-infinity, 3.5, "c1"); c1->SetCoefficient(x, 1); c1->SetCoefficient(y, 0); LOG(INFO) << "Number of constraints = " << solver->NumConstraints();
Java
// x + 7 * y <= 17.5. MPConstraint c0 = solver.makeConstraint(-infinity, 17.5, "c0"); c0.setCoefficient(x, 1); c0.setCoefficient(y, 7); // x <= 3.5. MPConstraint c1 = solver.makeConstraint(-infinity, 3.5, "c1"); c1.setCoefficient(x, 1); c1.setCoefficient(y, 0); System.out.println("Number of constraints = " + solver.numConstraints());
C#
// x + 7 * y <= 17.5. solver.Add(x + 7 * y <= 17.5); // x <= 3.5. solver.Add(x <= 3.5); Console.WriteLine("Number of constraints = " + solver.NumConstraints());
Ziel definieren
Der folgende Code definiert die objective function
für das Problem.
Python
# Maximize x + 10 * y. solver.Maximize(x + 10 * y)
C++
// Maximize x + 10 * y. MPObjective* const objective = solver->MutableObjective(); objective->SetCoefficient(x, 1); objective->SetCoefficient(y, 10); objective->SetMaximization();
Java
// Maximize x + 10 * y. MPObjective objective = solver.objective(); objective.setCoefficient(x, 1); objective.setCoefficient(y, 10); objective.setMaximization();
C#
// Maximize x + 10 * y. solver.Maximize(x + 10 * y);
Matherechner aufrufen
Mit dem folgenden Code wird der Solver aufgerufen.
Python
print(f"Solving with {solver.SolverVersion()}") status = solver.Solve()
C++
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!"; }
Java
final MPSolver.ResultStatus resultStatus = solver.solve();
C#
Solver.ResultStatus resultStatus = solver.Solve();
Lösung anzeigen
Der folgende Code zeigt die Lösung an.
Python
if status == pywraplp.Solver.OPTIMAL: print("Solution:") print("Objective value =", solver.Objective().Value()) print("x =", x.solution_value()) print("y =", y.solution_value()) else: print("The problem does not have an optimal solution.")
C++
LOG(INFO) << "Solution:"; LOG(INFO) << "Objective value = " << objective->Value(); LOG(INFO) << "x = " << x->solution_value(); LOG(INFO) << "y = " << y->solution_value();
Java
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!"); }
C#
// 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());
Hier ist die Lösung für dieses Problem.
Number of variables = 2 Number of constraints = 2 Solution: Objective value = 23 x = 3 y = 2
Der optimale Wert der Zielfunktion ist 23, der an der Stelle x = 3
, y = 2
, auftritt.
Abgeschlossene Programme
Hier sind die vollständigen Programme.
Python
from ortools.linear_solver import pywraplp def main(): # Create the mip solver with the SCIP backend. solver = pywraplp.Solver.CreateSolver("SAT") if not solver: return 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) print(f"Solving with {solver.SolverVersion()}") status = solver.Solve() if status == pywraplp.Solver.OPTIMAL: print("Solution:") print("Objective value =", solver.Objective().Value()) print("x =", x.solution_value()) print("y =", y.solution_value()) 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") print(f"Problem solved in {solver.nodes():d} branch-and-bound nodes") if __name__ == "__main__": main()
C++
#include <memory> #include "ortools/linear_solver/linear_solver.h" namespace operations_research { void SimpleMipProgram() { // Create the mip solver with the SCIP backend. 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 integer non-negative variables. MPVariable* const x = solver->MakeIntVar(0.0, infinity, "x"); MPVariable* const y = solver->MakeIntVar(0.0, infinity, "y"); LOG(INFO) << "Number of variables = " << solver->NumVariables(); // x + 7 * y <= 17.5. MPConstraint* const c0 = solver->MakeRowConstraint(-infinity, 17.5, "c0"); c0->SetCoefficient(x, 1); c0->SetCoefficient(y, 7); // x <= 3.5. MPConstraint* const c1 = solver->MakeRowConstraint(-infinity, 3.5, "c1"); c1->SetCoefficient(x, 1); c1->SetCoefficient(y, 0); LOG(INFO) << "Number of constraints = " << solver->NumConstraints(); // Maximize x + 10 * y. MPObjective* const objective = solver->MutableObjective(); objective->SetCoefficient(x, 1); objective->SetCoefficient(y, 10); 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) << "Objective value = " << objective->Value(); LOG(INFO) << "x = " << x->solution_value(); LOG(INFO) << "y = " << y->solution_value(); LOG(INFO) << "\nAdvanced usage:"; LOG(INFO) << "Problem solved in " << solver->wall_time() << " milliseconds"; LOG(INFO) << "Problem solved in " << solver->iterations() << " iterations"; LOG(INFO) << "Problem solved in " << solver->nodes() << " branch-and-bound nodes"; } } // namespace operations_research int main(int argc, char** argv) { operations_research::SimpleMipProgram(); return EXIT_SUCCESS; }
Java
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; /** Minimal Mixed Integer Programming example to showcase calling the solver. */ public final class SimpleMipProgram { public static void main(String[] args) { Loader.loadNativeLibraries(); // Create the linear solver with the SCIP backend. MPSolver solver = MPSolver.createSolver("SCIP"); if (solver == null) { System.out.println("Could not create solver SCIP"); return; } double infinity = java.lang.Double.POSITIVE_INFINITY; // x and y are integer non-negative variables. MPVariable x = solver.makeIntVar(0.0, infinity, "x"); MPVariable y = solver.makeIntVar(0.0, infinity, "y"); System.out.println("Number of variables = " + solver.numVariables()); // x + 7 * y <= 17.5. MPConstraint c0 = solver.makeConstraint(-infinity, 17.5, "c0"); c0.setCoefficient(x, 1); c0.setCoefficient(y, 7); // x <= 3.5. MPConstraint c1 = solver.makeConstraint(-infinity, 3.5, "c1"); c1.setCoefficient(x, 1); c1.setCoefficient(y, 0); System.out.println("Number of constraints = " + solver.numConstraints()); // Maximize x + 10 * y. MPObjective objective = solver.objective(); objective.setCoefficient(x, 1); objective.setCoefficient(y, 10); 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"); System.out.println("Problem solved in " + solver.nodes() + " branch-and-bound nodes"); } private SimpleMipProgram() {} }
C#
using System; using Google.OrTools.LinearSolver; public class SimpleMipProgram { static void Main() { // Create the linear solver with the SCIP backend. Solver solver = Solver.CreateSolver("SCIP"); if (solver is null) { return; } // x and y are integer non-negative variables. Variable x = solver.MakeIntVar(0.0, double.PositiveInfinity, "x"); Variable y = solver.MakeIntVar(0.0, double.PositiveInfinity, "y"); Console.WriteLine("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); Console.WriteLine("Number of constraints = " + solver.NumConstraints()); // Maximize x + 10 * y. solver.Maximize(x + 10 * 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"); Console.WriteLine("Problem solved in " + solver.Nodes() + " branch-and-bound nodes"); } }
Vergleich der linearen und der Ganzzahloptimierung
Vergleichen wir nun die Lösung mit dem oben gezeigten Optimierungsproblem der Ganzzahl und mit der Lösung für das entsprechende lineare Optimierungsproblem, bei dem Ganzzahleinschränkungen entfernt werden. Sie vermuten, dass die Lösung des Ganzzahlproblems der Ganzzahlpunkt in der realisierbaren Region wäre, die der linearen Lösung am nächsten ist – also der Punkt x = 0
, y = 2
. Aber wie Sie gleich sehen werden, ist dies nicht der Fall.
Sie können das Programm im vorherigen Abschnitt ganz einfach ändern, um das lineare Problem zu lösen. Nehmen Sie dazu die folgenden Änderungen vor:
- MIP-Rechner ersetzen
Python
# Create the mip solver with the SCIP backend. solver = pywraplp.Solver.CreateSolver("SAT") if not solver: return
C++
// Create the mip solver with the SCIP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("SCIP")); if (!solver) { LOG(WARNING) << "SCIP solver unavailable."; return; }
Java
// Create the linear solver with the SCIP backend. MPSolver solver = MPSolver.createSolver("SCIP"); if (solver == null) { System.out.println("Could not create solver SCIP"); return; }
C#
// Create the linear solver with the SCIP backend. Solver solver = Solver.CreateSolver("SCIP"); if (solver is null) { return; }
Python
# Create the linear solver with the GLOP backend. solver = pywraplp.Solver.CreateSolver("GLOP") if not solver: return
C++
// Create the linear solver with the GLOP backend. std::unique_ptr<MPSolver> solver(MPSolver::CreateSolver("GLOP"));
Java
// Create the linear solver with the GLOP backend. MPSolver solver = MPSolver.createSolver("GLOP"); if (solver == null) { System.out.println("Could not create solver SCIP"); return; }
C#
// Create the linear solver with the GLOP backend. Solver solver = Solver.CreateSolver("GLOP"); if (solver is null) { return; }
- Ganzzahlvariablen ersetzen
Python
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())
C++
const double infinity = solver->infinity(); // x and y are integer non-negative variables. MPVariable* const x = solver->MakeIntVar(0.0, infinity, "x"); MPVariable* const y = solver->MakeIntVar(0.0, infinity, "y"); LOG(INFO) << "Number of variables = " << solver->NumVariables();
Java
double infinity = java.lang.Double.POSITIVE_INFINITY; // x and y are integer non-negative variables. MPVariable x = solver.makeIntVar(0.0, infinity, "x"); MPVariable y = solver.makeIntVar(0.0, infinity, "y"); System.out.println("Number of variables = " + solver.numVariables());
C#
// x and y are integer non-negative variables. Variable x = solver.MakeIntVar(0.0, double.PositiveInfinity, "x"); Variable y = solver.MakeIntVar(0.0, double.PositiveInfinity, "y"); Console.WriteLine("Number of variables = " + solver.NumVariables());
Python
infinity = solver.infinity() # Create the variables x and y. x = solver.NumVar(0.0, infinity, "x") y = solver.NumVar(0.0, infinity, "y") print("Number of variables =", solver.NumVariables())
C++
const double infinity = solver->infinity(); // Create the variables x and y. 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();
Java
double infinity = java.lang.Double.POSITIVE_INFINITY; // Create the variables x and y. MPVariable x = solver.makeNumVar(0.0, infinity, "x"); MPVariable y = solver.makeNumVar(0.0, infinity, "y"); System.out.println("Number of variables = " + solver.numVariables());
C#
// Create the variables x and y. 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());
Nachdem Sie diese Änderungen vorgenommen und das Programm noch einmal ausgeführt haben, erhalten Sie die folgende Ausgabe:
Number of variables = 2 Number of constraints = 2 Objective value = 25.000000 x = 0.000000 y = 2.500000
Die Lösung des linearen Problems tritt an dem Punkt x = 0
, y = 2.5
, auf, an dem die Zielfunktion 25 ist. Diese Grafik zeigt die Lösungen
für die linearen und ganzzahligen Probleme.
Beachten Sie, dass die Ganzzahllösung im Vergleich zu den meisten anderen Ganzzahlpunkten in der zulässigen Region nicht nahe an der linearen Lösung liegt. Im Allgemeinen können die Lösungen für ein lineares Optimierungsproblem und die entsprechenden ganzzahligen Optimierungsprobleme weit auseinanderliegen. Aus diesem Grund erfordern die beiden Arten von Problemen unterschiedliche Methoden für ihre Lösung.