tweak model_builder_helper
This commit is contained in:
@@ -33,21 +33,11 @@ rather than for solving specific optimization problems.
|
||||
|
||||
import math
|
||||
|
||||
from ortools.linear_solver import linear_solver_pb2
|
||||
from ortools.model_builder.python import model_builder_helper as mbh
|
||||
from ortools.model_builder.python import pywrap_model_builder_helper as pwmb
|
||||
|
||||
# Forward solve statuses.
|
||||
OPTIMAL = linear_solver_pb2.MPSOLVER_OPTIMAL
|
||||
FEASIBLE = linear_solver_pb2.MPSOLVER_FEASIBLE
|
||||
INFEASIBLE = linear_solver_pb2.MPSOLVER_INFEASIBLE
|
||||
UNBOUNDED = linear_solver_pb2.MPSOLVER_UNBOUNDED
|
||||
ABNORMAL = linear_solver_pb2.MPSOLVER_ABNORMAL
|
||||
NOT_SOLVED = linear_solver_pb2.MPSOLVER_NOT_SOLVED
|
||||
MODEL_IS_VALID = linear_solver_pb2.MPSOLVER_MODEL_IS_VALID
|
||||
CANCELLED_BY_USER = linear_solver_pb2.MPSOLVER_CANCELLED_BY_USER
|
||||
UNKNOWN_STATUS = linear_solver_pb2.MPSOLVER_UNKNOWN_STATUS
|
||||
MODEL_INVALID = linear_solver_pb2.MPSOLVER_MODEL_INVALID
|
||||
SolveStatus = pwmb.SolveStatus
|
||||
|
||||
|
||||
class LinearExpr(object):
|
||||
@@ -842,6 +832,7 @@ class ModelBuilder(object):
|
||||
|
||||
def __optimize(self, linear_expr, maximize):
|
||||
"""Defines the objective."""
|
||||
self.helper.clear_objective()
|
||||
coeffs_map = {}
|
||||
# constant = 0.0
|
||||
if isinstance(linear_expr, LinearExpr):
|
||||
@@ -943,7 +934,7 @@ class ModelSolver(object):
|
||||
if self.log_callback is not None:
|
||||
self.__solve_helper.set_log_callback(self.log_callback)
|
||||
self.__solve_helper.solve(model.helper)
|
||||
return self.__solve_helper.status()
|
||||
return SolveStatus(self.__solve_helper.status())
|
||||
|
||||
def __check_has_feasible_solution(self):
|
||||
"""Checks that solve has run and has found a feasible solution."""
|
||||
@@ -982,12 +973,6 @@ class ModelSolver(object):
|
||||
self.__check_has_feasible_solution()
|
||||
return self.__solve_helper.best_objective_bound()
|
||||
|
||||
def status_name(self, status=None):
|
||||
"""Returns the name of the status returned by solve()."""
|
||||
if status is None:
|
||||
status = self.__solve_helper.status()
|
||||
return linear_solver_pb2.MPSolverResponseStatus.Name(status)
|
||||
|
||||
@property
|
||||
def status_string(self):
|
||||
"""Returns additional information of the last solve.
|
||||
|
||||
@@ -37,6 +37,7 @@ using ::operations_research::MPModelProto;
|
||||
using ::operations_research::MPModelRequest;
|
||||
using ::operations_research::MPSolutionResponse;
|
||||
using ::operations_research::MPVariableProto;
|
||||
using ::operations_research::SolveStatus;
|
||||
using ::pybind11::arg;
|
||||
|
||||
// TODO(user): The interface uses serialized protos because of issues building
|
||||
@@ -190,12 +191,30 @@ PYBIND11_MODULE(pywrap_model_builder_helper, m) {
|
||||
&ModelBuilderHelper::ConstraintCoefficients, arg("ct_index"))
|
||||
.def("name", &ModelBuilderHelper::name)
|
||||
.def("set_name", &ModelBuilderHelper::SetName, arg("name"))
|
||||
.def("clear_objective", &ModelBuilderHelper::ClearObjective)
|
||||
.def("maximize", &ModelBuilderHelper::maximize)
|
||||
.def("set_maximize", &ModelBuilderHelper::SetMaximize, arg("maximize"))
|
||||
.def("set_objective_offset", &ModelBuilderHelper::SetObjectiveOffset,
|
||||
arg("offset"))
|
||||
.def("objective_offset", &ModelBuilderHelper::ObjectiveOffset);
|
||||
|
||||
pybind11::enum_<SolveStatus>(m, "SolveStatus")
|
||||
.value("OPTIMAL", SolveStatus::OPTIMAL)
|
||||
.value("FEASIBLE", SolveStatus::FEASIBLE)
|
||||
.value("INFEASIBLE", SolveStatus::INFEASIBLE)
|
||||
.value("UNBOUNDED", SolveStatus::UNBOUNDED)
|
||||
.value("ABNORMAL", SolveStatus::ABNORMAL)
|
||||
.value("NOT_SOLVED", SolveStatus::NOT_SOLVED)
|
||||
.value("MODEL_IS_VALID", SolveStatus::MODEL_IS_VALID)
|
||||
.value("CANCELLED_BY_USER", SolveStatus::CANCELLED_BY_USER)
|
||||
.value("UNKNOWN_STATUS", SolveStatus::UNKNOWN_STATUS)
|
||||
.value("MODEL_INVALID", SolveStatus::MODEL_INVALID)
|
||||
.value("INVALID_SOLVER_PARAMETERS",
|
||||
SolveStatus::INVALID_SOLVER_PARAMETERS)
|
||||
.value("SOLVER_TYPE_UNAVAILABLE", SolveStatus::SOLVER_TYPE_UNAVAILABLE)
|
||||
.value("INCOMPATIBLE_OPTIONS", SolveStatus::INCOMPATIBLE_OPTIONS)
|
||||
.export_values();
|
||||
|
||||
pybind11::class_<ModelSolverHelper>(m, "ModelSolverHelper")
|
||||
.def(pybind11::init<const std::string&>())
|
||||
.def("solver_is_supported", &ModelSolverHelper::SolverIsSupported)
|
||||
|
||||
@@ -75,7 +75,8 @@ def main():
|
||||
|
||||
# Print solution.
|
||||
# [START print_solution]
|
||||
if status == model_builder.OPTIMAL or status == model_builder.FEASIBLE:
|
||||
if (status == model_builder.SolveStatus.OPTIMAL or
|
||||
status == model_builder.SolveStatus.FEASIBLE):
|
||||
print(f'Total cost = {solver.objective_value}\n')
|
||||
for i in range(num_workers):
|
||||
for j in range(num_tasks):
|
||||
|
||||
@@ -84,7 +84,7 @@ def main():
|
||||
# [END solve]
|
||||
|
||||
# [START print_solution]
|
||||
if status == model_builder.OPTIMAL:
|
||||
if status == model_builder.SolveStatus.OPTIMAL:
|
||||
num_bins = 0.
|
||||
for j in data['bins']:
|
||||
if solver.value(y[j]) == 1:
|
||||
|
||||
@@ -56,7 +56,7 @@ def main():
|
||||
# [END solve]
|
||||
|
||||
# [START print_solution]
|
||||
if status == model_builder.OPTIMAL:
|
||||
if status == model_builder.SolveStatus.OPTIMAL:
|
||||
print('Solution:')
|
||||
print('Objective value =', solver.objective_value)
|
||||
print('x =', solver.value(x))
|
||||
|
||||
@@ -56,7 +56,7 @@ def main():
|
||||
# [END solve]
|
||||
|
||||
# [START print_solution]
|
||||
if status == model_builder.OPTIMAL:
|
||||
if status == model_builder.SolveStatus.OPTIMAL:
|
||||
print('Solution:')
|
||||
print('Objective value =', solver.objective_value)
|
||||
print('x =', solver.value(x))
|
||||
|
||||
@@ -199,6 +199,11 @@ std::string ModelBuilderHelper::name() const { return model_.name(); }
|
||||
void ModelBuilderHelper::SetName(const std::string& name) {
|
||||
model_.set_name(name);
|
||||
}
|
||||
void ModelBuilderHelper::ClearObjective() {
|
||||
for (MPVariableProto& var : *model_.mutable_variable()) {
|
||||
var.clear_objective_coefficient();
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelBuilderHelper::maximize() const { return model_.maximize(); }
|
||||
|
||||
@@ -221,6 +226,43 @@ std::optional<MPSolutionResponse> ModelSolverHelper::SolveRequest(
|
||||
return temp;
|
||||
}
|
||||
|
||||
namespace {
|
||||
SolveStatus MPSolverResponseStatusToSolveStatus(MPSolverResponseStatus s) {
|
||||
switch (s) {
|
||||
case MPSOLVER_OPTIMAL:
|
||||
return SolveStatus::OPTIMAL;
|
||||
case MPSOLVER_FEASIBLE:
|
||||
return SolveStatus::FEASIBLE;
|
||||
case MPSOLVER_INFEASIBLE:
|
||||
return SolveStatus::INFEASIBLE;
|
||||
case MPSOLVER_UNBOUNDED:
|
||||
return SolveStatus::UNBOUNDED;
|
||||
case MPSOLVER_ABNORMAL:
|
||||
return SolveStatus::ABNORMAL;
|
||||
case MPSOLVER_NOT_SOLVED:
|
||||
return SolveStatus::NOT_SOLVED;
|
||||
case MPSOLVER_MODEL_IS_VALID:
|
||||
return SolveStatus::MODEL_IS_VALID;
|
||||
case MPSOLVER_CANCELLED_BY_USER:
|
||||
return SolveStatus::CANCELLED_BY_USER;
|
||||
case MPSOLVER_UNKNOWN_STATUS:
|
||||
return SolveStatus::UNKNOWN_STATUS;
|
||||
case MPSOLVER_MODEL_INVALID:
|
||||
return SolveStatus::MODEL_INVALID;
|
||||
case MPSOLVER_MODEL_INVALID_SOLUTION_HINT:
|
||||
return SolveStatus::MODEL_INVALID;
|
||||
case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS:
|
||||
return SolveStatus::INVALID_SOLVER_PARAMETERS;
|
||||
case MPSOLVER_SOLVER_TYPE_UNAVAILABLE:
|
||||
return SolveStatus::SOLVER_TYPE_UNAVAILABLE;
|
||||
case MPSOLVER_INCOMPATIBLE_OPTIONS:
|
||||
return SolveStatus::INCOMPATIBLE_OPTIONS;
|
||||
default:
|
||||
return SolveStatus::UNKNOWN_STATUS;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ModelSolverHelper::ModelSolverHelper(const std::string& solver_name) {
|
||||
if (solver_name.empty()) return;
|
||||
MPSolver::OptimizationProblemType parsed_type;
|
||||
@@ -318,11 +360,11 @@ const MPSolutionResponse& ModelSolverHelper::response() const {
|
||||
return response_.value();
|
||||
}
|
||||
|
||||
MPSolverResponseStatus ModelSolverHelper::status() const {
|
||||
SolveStatus ModelSolverHelper::status() const {
|
||||
if (!response_.has_value()) {
|
||||
return MPSolverResponseStatus::MPSOLVER_UNKNOWN_STATUS;
|
||||
return SolveStatus::UNKNOWN_STATUS;
|
||||
}
|
||||
return response_.value().status();
|
||||
return MPSolverResponseStatusToSolveStatus(response_.value().status());
|
||||
}
|
||||
|
||||
double ModelSolverHelper::objective_value() const {
|
||||
|
||||
@@ -91,6 +91,7 @@ class ModelBuilderHelper {
|
||||
std::string name() const;
|
||||
void SetName(const std::string& name);
|
||||
|
||||
void ClearObjective();
|
||||
bool maximize() const;
|
||||
void SetMaximize(bool maximize);
|
||||
double ObjectiveOffset() const;
|
||||
@@ -107,6 +108,22 @@ class LogCallback {
|
||||
virtual void NewMessage(const std::string& message) = 0;
|
||||
};
|
||||
|
||||
enum SolveStatus {
|
||||
OPTIMAL,
|
||||
FEASIBLE,
|
||||
INFEASIBLE,
|
||||
UNBOUNDED,
|
||||
ABNORMAL,
|
||||
NOT_SOLVED,
|
||||
MODEL_IS_VALID,
|
||||
CANCELLED_BY_USER,
|
||||
UNKNOWN_STATUS,
|
||||
MODEL_INVALID,
|
||||
INVALID_SOLVER_PARAMETERS,
|
||||
SOLVER_TYPE_UNAVAILABLE,
|
||||
INCOMPATIBLE_OPTIONS,
|
||||
};
|
||||
|
||||
// Class used to solve a request. This class is not meant to be exposed to the
|
||||
// public. Its responsibility is to bridge the MPModelProto in the non-C++
|
||||
// languages with the C++ Solve method.
|
||||
@@ -133,7 +150,7 @@ class ModelSolverHelper {
|
||||
bool has_response() const;
|
||||
bool has_solution() const;
|
||||
const MPSolutionResponse& response() const;
|
||||
MPSolverResponseStatus status() const;
|
||||
SolveStatus status() const;
|
||||
|
||||
// If not defined, or no solution, they will silently return 0.
|
||||
double objective_value() const;
|
||||
|
||||
Reference in New Issue
Block a user