ส่วนต่อไปนี้แสดงตัวอย่างปัญหา MIP และแสดงวิธีแก้โจทย์ ปัญหามีดังต่อไปนี้
เพิ่ม x + 10y
ให้มากที่สุดภายใต้ข้อจำกัดต่อไปนี้
x + 7y
≤ 17.5- 0 ≤
x
≤ 3.5 - 0 ≤
y
x
, จำนวนเต็มy
รายการ
เนื่องจากข้อจำกัดเป็นแบบเชิงเส้น นี่จึงเป็นเพียงปัญหาการเพิ่มประสิทธิภาพเชิงเส้นเท่านั้น ซึ่งคำตอบนั้นต้องเป็นจำนวนเต็ม กราฟด้านล่างแสดงจุดจำนวนเต็มในบริเวณที่เป็นไปได้ของปัญหา
โปรดสังเกตว่าปัญหานี้คล้ายกับโจทย์การเพิ่มประสิทธิภาพเชิงเส้นมากที่อธิบายไว้ในการแก้ปัญหาหน้า LP แต่ในกรณีนี้เราต้องการคำตอบที่เป็นจำนวนเต็ม
ขั้นตอนพื้นฐานสำหรับการแก้ปัญหา MIP
หากต้องการแก้ไขปัญหา MIP โปรแกรมของคุณควรมีขั้นตอนต่อไปนี้
- นำเข้า Wrapper ของตัวแก้วิดีโอเชิงเส้น
- ประกาศเครื่องมือแก้โจทย์ MIP
- กำหนดตัวแปร
- กำหนดข้อจำกัด
- กำหนดวัตถุประสงค์
- เรียกใช้โปรแกรมแก้ MIP และ
- แสดงโซลูชัน
โซลูชันที่ใช้ MPSolver
ส่วนต่อไปนี้จะแสดงโปรแกรมที่แก้ปัญหาโดยใช้ Wrapper ของ MPSolver และเครื่องมือแก้โจทย์ MIP
โปรแกรมแก้โจทย์ MIP ของ OR-Tools เริ่มต้นคือ SCIP
นำเข้า Wrapper เครื่องมือแก้โจทย์เชิงเส้น
นำเข้า (หรือรวม) Wrapper เครื่องมือแก้โจทย์เชิงเส้น "หรือ" ซึ่งเป็นอินเทอร์เฟซสำหรับเครื่องมือแก้ปัญหา MIP และเครื่องมือแก้โจทย์เชิงเส้นดังที่แสดงด้านล่าง
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
โค้ดต่อไปนี้ประกาศโปรแกรมแก้ MIP ของโจทย์ ตัวอย่างนี้ใช้ SCIP ซึ่งเป็นเครื่องมือแก้โจทย์ของบุคคลที่สาม
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
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());
โปรแกรมจะใช้เมธอด MakeIntVar
(หรือตัวแปรโดยขึ้นอยู่กับภาษาที่เขียนโค้ด) เพื่อสร้างตัวแปร x
และ y
ที่ใช้ค่าจำนวนเต็มที่ไม่ติดลบ
กําหนดข้อจํากัด
รหัสต่อไปนี้จะระบุข้อจำกัดสำหรับปัญหาดังกล่าว
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());
กําหนดวัตถุประสงค์
รหัสต่อไปนี้กำหนด objective function
สำหรับปัญหาดังกล่าว
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);
เรียกใช้เครื่องมือแก้โจทย์
โค้ดต่อไปนี้จะเรียกตัวแก้โจทย์
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();
แสดงคำตอบ
โค้ดต่อไปนี้จะแสดงโซลูชัน
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());
วิธีแก้ปัญหามีดังนี้
Number of variables = 2 Number of constraints = 2 Solution: Objective value = 23 x = 3 y = 2
ค่าที่เหมาะสมที่สุดของฟังก์ชันวัตถุประสงค์คือ 23 ซึ่งจะเกิดขึ้นที่จุด x = 3
, y = 2
เข้าร่วมโปรแกรม
โปรแกรมทั้งหมดมีดังนี้
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"); } }
การเปรียบเทียบการเพิ่มประสิทธิภาพเชิงเส้นและจำนวนเต็ม
มาเปรียบเทียบวิธีการแก้โจทย์การเพิ่มประสิทธิภาพจำนวนเต็มที่แสดงด้านบนกับวิธีแก้ปัญหาการเพิ่มประสิทธิภาพเชิงเส้นที่ตรงกัน ซึ่งมีการนำข้อจำกัดจำนวนเต็มออก คุณอาจเดาได้ว่าคำตอบของจำนวนเต็มจะเป็นจุดจำนวนเต็มในภูมิภาคที่เป็นไปได้และใกล้กับคำตอบเชิงเส้นที่สุด นั่นคือจุด x = 0
ซึ่งก็คือ y = 2
แต่อย่างที่คุณจะเห็นในลำดับต่อไป
คงไม่เป็นเช่นนั้นแล้ว
คุณแก้ไขโปรแกรมในส่วนก่อนหน้าเพื่อแก้ปัญหาเชิงเส้นได้ง่ายๆ โดยทำการเปลี่ยนแปลงต่อไปนี้
- แทนที่เครื่องมือแก้โจทย์ MIP
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; }
- แทนที่ตัวแปรจำนวนเต็ม
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());
หลังจากทำการเปลี่ยนแปลงเหล่านี้และเรียกใช้โปรแกรมอีกครั้งแล้ว คุณจะได้ผลลัพธ์ต่อไปนี้
Number of variables = 2 Number of constraints = 2 Objective value = 25.000000 x = 0.000000 y = 2.500000
การแก้โจทย์เชิงเส้นจะเกิดขึ้นที่จุด x = 0
ซึ่งเท่ากับ y = 2.5
ซึ่งฟังก์ชันวัตถุประสงค์เท่ากับ 25 นี่คือกราฟแสดงวิธีแก้ปัญหาทั้ง
แบบเชิงเส้นและจำนวนเต็ม
โปรดสังเกตว่าคำตอบที่เป็นจำนวนเต็มไม่ได้ใกล้เคียงกับผลเฉลยเชิงเส้น เมื่อเทียบกับจุดที่เป็นจำนวนเต็มอื่นๆ ส่วนใหญ่ในบริเวณที่เป็นไปได้ โดยทั่วไป วิธีแก้ปัญหาการเพิ่มประสิทธิภาพเชิงเส้นและปัญหาการเพิ่มประสิทธิภาพจำนวนเต็มที่เกี่ยวข้องอาจอยู่ห่างกันมาก ด้วยเหตุนี้ ปัญหาทั้ง 2 ประเภทนี้จึงต้องการ วิธีแก้ปัญหาที่ต่างกัน