תחילת העבודה

בדוגמה הזו מוסבר איך ליצור, לפתור ולבדוק את התוצאות של תוכנית לינארית פשוטה (LP) באמצעות MathOpt. מידע על התקנת OR-Tools זמין במדריך ההתקנה. הערות נוספות לגבי אופן היצירה וההרצה מ-source נדחות לקראת הסוף.

בניית מודל MathOpt

במקור, צריך להוסיף בדרך כלל רק תלות אחת של MathOpt:

Python

from ortools.math_opt.python import mathopt

C++

#include <iostream>
#include <ostream>

#include "absl/log/check.h"
#include "absl/status/statusor.h"
#include "ortools/base/init_google.h"
#include "ortools/math_opt/cpp/math_opt.h"

במדריך הזה נשתמש בבעיית התכנות הלינארית הבאה, ונפתרת אותה באמצעות GLOP.

$$\begin{aligned} &\max &x + 2 \cdot y\\ &\text{subject to} &x + y &\leq 1.5 \\ &&-1 \leq x &\leq 1.5 \\ &&0 \leq y &\leq 1 \end{aligned}$$

קודם כול, בונים את המודל:

Python

# Build the model.
model = mathopt.Model(name="getting_started_lp")
x = model.add_variable(lb=-1.0, ub=1.5, name="x")
y = model.add_variable(lb=0.0, ub=1.0, name="y")
model.add_linear_constraint(x + y <= 1.5)
model.maximize(x + 2 * y)

C++

// Build the model.
namespace math_opt = ::operations_research::math_opt;
math_opt::Model lp_model("getting_started_lp");
const math_opt::Variable x = lp_model.AddContinuousVariable(-1.0, 1.5, "x");
const math_opt::Variable y = lp_model.AddContinuousVariable(0.0, 1.0, "y");
lp_model.AddLinearConstraint(x + y <= 1.5, "c");
lp_model.Maximize(x + 2 * y);

פתרון ובדיקת הפתרון

לאחר מכן, מגדירים את הפרמטרים לפתרון. פתרון בעיות מודלים של אופטימיזציה באמצעות MathOpt ניתן להגדרה רבה. יש פרמטרים בלתי תלויים בפותר (למשל, הפעלת פלט), פרמטרים ספציפיים לפותר (למשל GlopParameters.optimization_rule), פרמטרים שתלויים במאפיינים של המודל (למשל עדיפות להסתעפות), קריאה חוזרת (callback) ליומני הפותר וקריאה חוזרת (callback) למעקב אחרי האופטימיזציה ולשליטה בה. הקוד הבא מפעיל את יומני הפותר.

Python

# Set parameters, e.g. turn on logging.
params = mathopt.SolveParameters(enable_output=True)

C++

// Set parameters, e.g. turn on logging.
math_opt::SolveArguments args;
args.parameters.enable_output = true;

כדי לפתור את הבעיה באמצעות GLOP, הכלי של Google לפתרון LP שמבוסס על חד-צדדי, צריך להשתמש בפונקציה Solve().

Python

# Solve and ensure an optimal solution was found with no errors.
# (mathopt.solve may raise a RuntimeError on invalid input or internal solver
# errors.)
result = mathopt.solve(model, mathopt.SolverType.GLOP, params=params)
if result.termination.reason != mathopt.TerminationReason.OPTIMAL:
    raise RuntimeError(f"model failed to solve: {result.termination}")

C++

// Solve and ensure an optimal solution was found with no errors.
const absl::StatusOr<math_opt::SolveResult> result =
    math_opt::Solve(lp_model, math_opt::SolverType::kGlop, args);
CHECK_OK(result.status());
CHECK_OK(result->termination.EnsureIsOptimal());

לבסוף, חשוב לבדוק את הערך האובייקטיבי של הפתרון האופטימלי ואת ערכי המשתנים האופטימליים. שימו לב: מכיוון שסיבת הסיום הייתה אופטימלית, אפשר להניח שהערכים האלה קיימים, אבל מסיבות אחרות של סיום (לדוגמה, בלתי מעשיות או בלתי מוגבלות), הקריאות לשיטות האלה יכולות CHECK fail (ב-C++ ) או raise an exception (ב-Python).

Python

# Print some information from the result.
print("MathOpt solve succeeded")
print("Objective value:", result.objective_value())
print("x:", result.variable_values()[x])
print("y:", result.variable_values()[y])

C++

// Print some information from the result.
std::cout << "MathOpt solve succeeded" << std::endl;
std::cout << "Objective value: " << result->objective_value() << std::endl;
std::cout << "x: " << result->variable_values().at(x) << std::endl;
std::cout << "y: " << result->variable_values().at(y) << std::endl;

הערות לגבי יצירה והרצה של הקוד באמצעות Bazel

אם יוצרים את MathOpt ממקור באמצעות bazel, הדוגמה הזו צריכה את יחסי התלות הבאים ביעד ה-build:

Python

"//util/operations_research/math_opt/python:mathopt"

C++

"//util/operations_research/math_opt/cpp:math_opt"
"//util/operations_research/math_opt/solvers:glop_solver"

כדי להריץ את הקוד, פקודת ה-bazel הבאה יוצרת ומריצה את היעד.

Python

bazel run path/to/you:target --with_scip=false --with_cp_sat=false
--with_glpk=false --with_glop=true -- --your_flags

C++

bazel run path/to/you:target -- --your_flags