Phần này mô tả trình giải quyết lập trình ràng buộc ban đầu, đã được thay thế bằng trình giải CP-SAT ưu việt.
Các phần sau mô tả cách giải quyết ví dụ được mô tả trong phần CP-SAT. Lần này, chúng tôi sử dụng trình phân giải CP ban đầu. Nếu vẫn muốn dùng trình giải CP gốc, bạn có thể duyệt xem tài liệu tham khảo API. Lưu ý rằng trình phân giải CP gốc là nền tảng của thư viện định tuyến và có thể cần có API của thư viện này để tuỳ chỉnh mô hình định tuyến.
Nhập thư viện
Mã sau đây nhập thư viện bắt buộc.
Python
from ortools.constraint_solver import pywrapcp
C++
#include <ostream> #include <string> #include "ortools/constraint_solver/constraint_solver.h"
Java
import com.google.ortools.Loader; import com.google.ortools.constraintsolver.DecisionBuilder; import com.google.ortools.constraintsolver.IntVar; import com.google.ortools.constraintsolver.Solver; import java.util.logging.Logger;
C#
using System; using Google.OrTools.ConstraintSolver;
Khai báo trình giải
Mã sau đây khai báo trình giải quyết.
Python
solver = pywrapcp.Solver("CPSimple")
C++
Solver solver("CpSimple");
Java
Solver solver = new Solver("CpSimple");
C#
Solver solver = new Solver("CpSimple");
Tạo các biến
Đoạn mã sau đây sẽ tạo các biến cho bài toán này.
Trình giải toán sẽ tạo ra 3 biến là x, y và z, mỗi biến có thể nhận các giá trị 0, 1 hoặc 2.
Python
num_vals = 3 x = solver.IntVar(0, num_vals - 1, "x") y = solver.IntVar(0, num_vals - 1, "y") z = solver.IntVar(0, num_vals - 1, "z")
C++
const int64_t num_vals = 3; IntVar* const x = solver.MakeIntVar(0, num_vals - 1, "x"); IntVar* const y = solver.MakeIntVar(0, num_vals - 1, "y"); IntVar* const z = solver.MakeIntVar(0, num_vals - 1, "z");
Java
final long numVals = 3; final IntVar x = solver.makeIntVar(0, numVals - 1, "x"); final IntVar y = solver.makeIntVar(0, numVals - 1, "y"); final IntVar z = solver.makeIntVar(0, numVals - 1, "z");
C#
const long numVals = 3; IntVar x = solver.MakeIntVar(0, numVals - 1, "x"); IntVar y = solver.MakeIntVar(0, numVals - 1, "y"); IntVar z = solver.MakeIntVar(0, numVals - 1, "z");
Tạo quy tắc ràng buộc
Đoạn mã sau đây sẽ tạo ra một điều kiện ràng buộc x ≠ y
.
Python
solver.Add(x != y) print("Number of constraints: ", solver.Constraints())
C++
solver.AddConstraint(solver.MakeAllDifferent({x, y})); LOG(INFO) << "Number of constraints: " << std::to_string(solver.constraints());
Java
solver.addConstraint(solver.makeAllDifferent(new IntVar[] {x, y})); logger.info("Number of constraints: " + solver.constraints());
C#
solver.Add(solver.MakeAllDifferent(new IntVar[] { x, y })); Console.WriteLine($"Number of constraints: {solver.Constraints()}");
Gọi trình giải toán
Mã sau đây gọi trình giải toán.
Trình tạo quyết định là dữ liệu đầu vào chính cho trình giải CP ban đầu. Hàm này chứa những thành phần sau:
vars
– Một mảng chứa các biến cho bài toán.- Quy tắc chọn biến tiếp theo để chỉ định giá trị.
- Quy tắc chọn giá trị tiếp theo để chỉ định cho biến đó.
Xem Trình tạo quyết định để biết thông tin chi tiết.
Python
decision_builder = solver.Phase( [x, y, z], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE )
C++
DecisionBuilder* const db = solver.MakePhase( {x, y, z}, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE);
Java
final DecisionBuilder db = solver.makePhase( new IntVar[] {x, y, z}, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);
C#
DecisionBuilder db = solver.MakePhase(new IntVar[] { x, y, z }, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);
In giải pháp
Mã cho máy in giải pháp (hiển thị từng giải pháp khi trình giải giải tìm thấy giải pháp đó) được hiển thị trong phần sau.
Vì có nhiều nghiệm cho bài toán của chúng ta, nên bạn có thể lặp lại các nghiệm bằng vòng lặp while solver.NextSolution()
. (Lưu ý rằng cách này hoạt động khác với máy in giải pháp cho trình giải CP-SAT).
Python
count = 0 solver.NewSearch(decision_builder) while solver.NextSolution(): count += 1 solution = f"Solution {count}:\n" for var in [x, y, z]: solution += f" {var.Name()} = {var.Value()}" print(solution) solver.EndSearch() print(f"Number of solutions found: {count}")
C++
int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; LOG(INFO) << "Solution " << count << ":" << std::endl << " x=" << x->Value() << " y=" << y->Value() << " z=" << z->Value(); } solver.EndSearch(); LOG(INFO) << "Number of solutions found: " << solver.solutions();
Java
int count = 0; solver.newSearch(db); while (solver.nextSolution()) { ++count; logger.info( String.format("Solution: %d\n x=%d y=%d z=%d", count, x.value(), y.value(), z.value())); } solver.endSearch(); logger.info("Number of solutions found: " + solver.solutions());
C#
int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; Console.WriteLine($"Solution: {count}\n x={x.Value()} y={y.Value()} z={z.Value()}"); } solver.EndSearch(); Console.WriteLine($"Number of solutions found: {solver.Solutions()}");
Kết quả do trình giải toán trả về
Sau đây là 18 giải pháp mà trình giải quyết tìm thấy:
Number of constraints: 1 Solution 1: x = 0 y = 1 z = 0 Solution 2: x = 0 y = 1 z = 1 Solution 3: x = 0 y = 1 z = 2 Solution 4: x = 0 y = 2 z = 0 Solution 5: x = 0 y = 2 z = 1 Solution 6: x = 0 y = 2 z = 2 Solution 7: x = 1 y = 0 z = 0 Solution 8: x = 1 y = 0 z = 1 Solution 9: x = 1 y = 0 z = 2 Solution 10: x = 1 y = 2 z = 0 Solution 11: x = 1 y = 2 z = 1 Solution 12: x = 1 y = 2 z = 2 Solution 13: x = 2 y = 0 z = 0 Solution 14: x = 2 y = 0 z = 1 Solution 15: x = 2 y = 0 z = 2 Solution 16: x = 2 y = 1 z = 0 Solution 17: x = 2 y = 1 z = 1 Solution 18: x = 2 y = 1 z = 2 Number of solutions found: 18 Advanced usage: Problem solved in 2 ms Memory usage: 13918208 bytes
Hoàn tất chương trình
Sau đây là chương trình hoàn chỉnh cho ví dụ sử dụng trình giải CP ban đầu.
Python
"""Simple Constraint optimization example.""" from ortools.constraint_solver import pywrapcp def main(): """Entry point of the program.""" # Instantiate the solver. solver = pywrapcp.Solver("CPSimple") # Create the variables. num_vals = 3 x = solver.IntVar(0, num_vals - 1, "x") y = solver.IntVar(0, num_vals - 1, "y") z = solver.IntVar(0, num_vals - 1, "z") # Constraint 0: x != y. solver.Add(x != y) print("Number of constraints: ", solver.Constraints()) # Solve the problem. decision_builder = solver.Phase( [x, y, z], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE ) # Print solution on console. count = 0 solver.NewSearch(decision_builder) while solver.NextSolution(): count += 1 solution = f"Solution {count}:\n" for var in [x, y, z]: solution += f" {var.Name()} = {var.Value()}" print(solution) solver.EndSearch() print(f"Number of solutions found: {count}") print("Advanced usage:") print(f"Problem solved in {solver.WallTime()}ms") print(f"Memory usage: {pywrapcp.Solver.MemoryUsage()}bytes") if __name__ == "__main__": main()
C++
#include <ostream> #include <string> #include "ortools/constraint_solver/constraint_solver.h" namespace operations_research { void SimpleCpProgram() { // Instantiate the solver. Solver solver("CpSimple"); // Create the variables. const int64_t num_vals = 3; IntVar* const x = solver.MakeIntVar(0, num_vals - 1, "x"); IntVar* const y = solver.MakeIntVar(0, num_vals - 1, "y"); IntVar* const z = solver.MakeIntVar(0, num_vals - 1, "z"); // Constraint 0: x != y.. solver.AddConstraint(solver.MakeAllDifferent({x, y})); LOG(INFO) << "Number of constraints: " << std::to_string(solver.constraints()); // Solve the problem. DecisionBuilder* const db = solver.MakePhase( {x, y, z}, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); // Print solution on console. int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; LOG(INFO) << "Solution " << count << ":" << std::endl << " x=" << x->Value() << " y=" << y->Value() << " z=" << z->Value(); } solver.EndSearch(); LOG(INFO) << "Number of solutions found: " << solver.solutions(); LOG(INFO) << "Advanced usage:" << std::endl << "Problem solved in " << std::to_string(solver.wall_time()) << "ms" << std::endl << "Memory usage: " << std::to_string(Solver::MemoryUsage()) << "bytes"; } } // namespace operations_research int main(int /*argc*/, char* /*argv*/[]) { operations_research::SimpleCpProgram(); return EXIT_SUCCESS; }
Java
package com.google.ortools.constraintsolver.samples; import com.google.ortools.Loader; import com.google.ortools.constraintsolver.DecisionBuilder; import com.google.ortools.constraintsolver.IntVar; import com.google.ortools.constraintsolver.Solver; import java.util.logging.Logger; /** Simple CP Program.*/ public class SimpleCpProgram { private SimpleCpProgram() {} private static final Logger logger = Logger.getLogger(SimpleCpProgram.class.getName()); public static void main(String[] args) throws Exception { Loader.loadNativeLibraries(); // Instantiate the solver. Solver solver = new Solver("CpSimple"); // Create the variables. final long numVals = 3; final IntVar x = solver.makeIntVar(0, numVals - 1, "x"); final IntVar y = solver.makeIntVar(0, numVals - 1, "y"); final IntVar z = solver.makeIntVar(0, numVals - 1, "z"); // Constraint 0: x != y.. solver.addConstraint(solver.makeAllDifferent(new IntVar[] {x, y})); logger.info("Number of constraints: " + solver.constraints()); // Solve the problem. final DecisionBuilder db = solver.makePhase( new IntVar[] {x, y, z}, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // Print solution on console. int count = 0; solver.newSearch(db); while (solver.nextSolution()) { ++count; logger.info( String.format("Solution: %d\n x=%d y=%d z=%d", count, x.value(), y.value(), z.value())); } solver.endSearch(); logger.info("Number of solutions found: " + solver.solutions()); logger.info(String.format("Advanced usage:\nProblem solved in %d ms\nMemory usage: %d bytes", solver.wallTime(), Solver.memoryUsage())); } }
C#
using System; using Google.OrTools.ConstraintSolver; /// <summary> /// This is a simple CP program. /// </summary> public class SimpleCpProgram { public static void Main(String[] args) { // Instantiate the solver. Solver solver = new Solver("CpSimple"); // Create the variables. const long numVals = 3; IntVar x = solver.MakeIntVar(0, numVals - 1, "x"); IntVar y = solver.MakeIntVar(0, numVals - 1, "y"); IntVar z = solver.MakeIntVar(0, numVals - 1, "z"); // Constraint 0: x != y.. solver.Add(solver.MakeAllDifferent(new IntVar[] { x, y })); Console.WriteLine($"Number of constraints: {solver.Constraints()}"); // Solve the problem. DecisionBuilder db = solver.MakePhase(new IntVar[] { x, y, z }, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // Print solution on console. int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; Console.WriteLine($"Solution: {count}\n x={x.Value()} y={y.Value()} z={z.Value()}"); } solver.EndSearch(); Console.WriteLine($"Number of solutions found: {solver.Solutions()}"); Console.WriteLine("Advanced usage:"); Console.WriteLine($"Problem solved in {solver.WallTime()}ms"); Console.WriteLine($"Memory usage: {Solver.MemoryUsage()}bytes"); } }
Trình tạo quyết định
Đầu vào chính cho trình giải quyết CP ban đầu là trình tạo quyết định. Trình tạo này chứa các biến cho bài toán và đặt ra các phương án cho trình giải toán.
Ví dụ về mã trong phần trước sẽ tạo một trình tạo quyết định bằng phương thức Phase
(tương ứng với phương thức C++ MakePhase
.
Cụm từ Giai đoạn đề cập đến một giai đoạn của quá trình tìm kiếm. Trong ví dụ đơn giản này, chỉ có một giai đoạn, nhưng đối với những bài toán phức tạp hơn, trình tạo quyết định có thể có nhiều giai đoạn để trình giải quyết có thể sử dụng nhiều chiến lược tìm kiếm từ giai đoạn này sang giai đoạn tiếp theo.
Phương thức Phase
có 3 tham số đầu vào:
vars
– Một mảng chứa các biến cho bài toán, trong trường hợp này là[x, y, z]
.IntVarStrategy
– Quy tắc để chọn biến không liên kết tiếp theo để gán giá trị. Ở đây, mã sử dụngCHOOSE_FIRST_UNBOUND
mặc định, nghĩa là ở mỗi bước, trình giải quyết sẽ chọn biến không liên kết đầu tiên theo thứ tự chúng xuất hiện trong mảng biến được truyền vào phương thứcPhase
.IntValueStrategy
– Quy tắc để chọn giá trị tiếp theo để gán cho một biến. Ở đây, mã sử dụngASSIGN_MIN_VALUE
mặc định để chọn giá trị nhỏ nhất chưa được thử cho biến. Thao tác này sẽ chỉ định các giá trị theo thứ tự tăng dần. Một cách khác làASSIGN_MAX_VALUE
, trong trường hợp đó, trình giải toán sẽ chỉ định các giá trị theo thứ tự giảm dần.