47 MPSolutionResponse response;
48 const absl::optional<LazyMutableCopy<MPModelProto>> optional_model =
50 if (!optional_model)
return response;
51 const MPModelProto&
model = **optional_model;
56 if (request->has_solver_specific_parameters()) {
58 request->solver_specific_parameters(), highs);
59 if (!parameters_status.ok()) {
60 response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
61 response.set_status_str(parameters_status.message());
66 if (request->solver_time_limit_seconds() > 0) {
67 HighsStatus
status = highs.setOptionValue(
68 "time_limit", request->solver_time_limit_seconds());
69 if (
status == HighsStatus::kError) {
70 response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
71 response.set_status_str(
"time_limit");
76 const int variable_size =
model.variable_size();
77 bool has_integer_variables =
false;
79 std::vector<double> obj_coeffs(variable_size, 0);
80 std::vector<double> lb(variable_size);
81 std::vector<double> ub(variable_size);
82 std::vector<HighsVarType> integrality(variable_size);
83 for (
int v = 0; v < variable_size; ++v) {
84 const MPVariableProto& variable =
model.variable(v);
85 obj_coeffs[v] = variable.objective_coefficient();
86 lb[v] = variable.lower_bound();
87 ub[v] = variable.upper_bound();
89 variable.is_integer() &&
90 request->solver_type() ==
91 MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING
92 ? HighsVarType::kInteger
93 : HighsVarType::kContinuous;
94 if (integrality[v] == HighsVarType::kInteger) {
95 has_integer_variables =
true;
99 highs.addVars(variable_size, lb.data(), ub.data());
102 if (has_integer_variables) {
103 for (
int v = 0; v < variable_size; ++v) {
104 highs.changeColIntegrality(v, integrality[v]);
118 for (
int c = 0; c <
model.constraint_size(); ++c) {
119 const MPConstraintProto& constraint =
model.constraint(c);
120 if (constraint.lower_bound() ==
121 -std::numeric_limits<double>::infinity()) {
123 highs.addRow(-kHighsInf,
124 constraint.upper_bound(),
125 constraint.var_index_size(),
126 constraint.var_index().data(),
127 constraint.coefficient().data());
128 if (
status == HighsStatus::kError) {
129 response.set_status(MPSOLVER_MODEL_INVALID);
130 response.set_status_str(
"ct addRow");
133 }
else if (constraint.upper_bound() ==
134 std::numeric_limits<double>::infinity()) {
136 highs.addRow(constraint.lower_bound(),
138 constraint.var_index_size(),
139 constraint.var_index().data(),
140 constraint.coefficient().data());
141 if (
status == HighsStatus::kError) {
142 response.set_status(MPSOLVER_MODEL_INVALID);
143 response.set_status_str(
"ct addRow");
148 highs.addRow(constraint.lower_bound(),
149 constraint.upper_bound(),
150 constraint.var_index_size(),
151 constraint.var_index().data(),
152 constraint.coefficient().data());
153 if (
status == HighsStatus::kError) {
154 response.set_status(MPSOLVER_MODEL_INVALID);
155 response.set_status_str(
"ct addRow");
162 if (!
model.general_constraint().empty()) {
163 response.set_status(MPSOLVER_MODEL_INVALID);
164 response.set_status_str(
"general constraints are not supported in Highs");
169 if (
model.maximize()) {
170 const ObjSense pass_sense = ObjSense::kMaximize;
171 highs.changeObjectiveSense(pass_sense);
174 if (
model.objective_offset()) {
175 const double offset =
model.objective_offset();
176 highs.changeObjectiveOffset(offset);
180 if (request->enable_internal_solver_output()) {
181 highs.setOptionValue(
"log_to_console",
true);
182 highs.setOptionValue(
"output_flag",
true);
184 highs.setOptionValue(
"log_to_console",
false);
185 highs.setOptionValue(
"output_flag",
false);
188 const absl::Time time_before = absl::Now();
191 HighsStatus run_status = highs.run();
192 switch (run_status) {
193 case HighsStatus::kError: {
194 response.set_status(MPSOLVER_NOT_SOLVED);
195 response.set_status_str(
"Error running HiGHS run()");
198 case HighsStatus::kWarning: {
199 response.set_status_str(
"Warning HiGHS run()");
202 case HighsStatus::kOk: {
203 HighsModelStatus model_status = highs.getModelStatus();
204 switch (model_status) {
205 case HighsModelStatus::kOptimal:
206 response.set_status(MPSOLVER_OPTIMAL);
208 case HighsModelStatus::kUnboundedOrInfeasible:
209 response.set_status_str(
210 "The model may actually be unbounded: HiGHS returned "
211 "kUnboundedOrInfeasible");
212 response.set_status(MPSOLVER_INFEASIBLE);
214 case HighsModelStatus::kInfeasible:
215 response.set_status(MPSOLVER_INFEASIBLE);
217 case HighsModelStatus::kUnbounded:
218 response.set_status(MPSOLVER_UNBOUNDED);
228 const absl::Duration solving_duration = absl::Now() - time_before;
230 response.mutable_solve_info()->set_solve_wall_time_seconds(
231 absl::ToDoubleSeconds(solving_duration));
232 response.mutable_solve_info()->set_solve_user_time_seconds(
235 if (response.status() == MPSOLVER_OPTIMAL) {
240 response.mutable_variable_value()->Resize(variable_size, 0);
242 response.mutable_variable_value()->mutable_data()[
column] =
243 highs.getSolution().col_value[
column];
246 if (has_integer_variables) {
247 for (
int v = 0; v < variable_size; ++v) {
248 if (
model.variable(v).is_integer()) {
249 response.set_variable_value(v,
250 std::round(response.variable_value(v)));
255 if (!has_integer_variables &&
model.general_constraint_size() == 0) {
256 response.mutable_dual_value()->Resize(
model.constraint_size(), 0);
258 response.set_dual_value(
row, highs.getSolution().row_value[
row]);