50 MPSolutionResponse response;
51 const std::optional<LazyMutableCopy<MPModelProto>> optional_model =
53 if (!optional_model)
return response;
54 const MPModelProto& model = **optional_model;
58 if (model.has_name()) {
59 const std::string model_name = model.name();
60 highs.passModelName(model_name);
63 if (request->has_solver_specific_parameters()) {
65 request->solver_specific_parameters(), highs);
66 if (!parameters_status.ok()) {
67 response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
68 response.set_status_str(parameters_status.message());
73 if (request->solver_time_limit_seconds() > 0) {
74 HighsStatus status = highs.setOptionValue(
75 "time_limit", request->solver_time_limit_seconds());
76 if (status == HighsStatus::kError) {
77 response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
78 response.set_status_str(
"time_limit");
83 const int variable_size = model.variable_size();
84 bool has_integer_variables =
false;
86 std::vector<double> obj_coeffs(variable_size, 0);
87 std::vector<double> lb(variable_size);
88 std::vector<double> ub(variable_size);
89 std::vector<HighsVarType> integrality(variable_size);
90 for (
int v = 0; v < variable_size; ++v) {
91 const MPVariableProto& variable = model.variable(v);
92 obj_coeffs[v] = variable.objective_coefficient();
93 lb[v] = variable.lower_bound();
94 ub[v] = variable.upper_bound();
96 variable.is_integer() &&
97 request->solver_type() ==
98 MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING
99 ? HighsVarType::kInteger
100 : HighsVarType::kContinuous;
101 if (integrality[v] == HighsVarType::kInteger) {
102 has_integer_variables =
true;
106 highs.addVars(variable_size, lb.data(), ub.data());
109 if (has_integer_variables) {
110 for (
int v = 0; v < variable_size; ++v) {
111 highs.changeColIntegrality(v, integrality[v]);
116 for (
int column = 0; column < variable_size; column++) {
117 highs.changeColCost(column, obj_coeffs[column]);
121 for (
int v = 0; v < variable_size; ++v) {
122 const MPVariableProto& variable = model.variable(v);
123 std::string varname_str =
"";
124 if (!variable.name().empty()) {
125 varname_str = variable.name();
126 highs.passColName(v, varname_str);
131 int num_hints = model.solution_hint().var_index_size();
133 std::vector<HighsInt> hint_index(0, num_hints);
134 std::vector<double> hint_value(0, num_hints);
135 for (
int i = 0; i < num_hints; ++i) {
136 hint_index[i] = model.solution_hint().var_index(i);
137 hint_value[i] = model.solution_hint().var_value(i);
139 const int* hint_indices = &hint_index[0];
140 const double* hint_values = &hint_value[0];
141 highs.setSolution((HighsInt)num_hints, hint_indices, hint_values);
146 for (
int c = 0; c < model.constraint_size(); ++c) {
147 const MPConstraintProto& constraint = model.constraint(c);
148 if (constraint.lower_bound() ==
149 -std::numeric_limits<double>::infinity()) {
151 highs.addRow(-kHighsInf,
152 constraint.upper_bound(),
153 constraint.var_index_size(),
154 constraint.var_index().data(),
155 constraint.coefficient().data());
156 if (status == HighsStatus::kError) {
157 response.set_status(MPSOLVER_MODEL_INVALID);
158 response.set_status_str(
"ct addRow");
161 }
else if (constraint.upper_bound() ==
162 std::numeric_limits<double>::infinity()) {
164 highs.addRow(constraint.lower_bound(),
166 constraint.var_index_size(),
167 constraint.var_index().data(),
168 constraint.coefficient().data());
169 if (status == HighsStatus::kError) {
170 response.set_status(MPSOLVER_MODEL_INVALID);
171 response.set_status_str(
"ct addRow");
176 highs.addRow(constraint.lower_bound(),
177 constraint.upper_bound(),
178 constraint.var_index_size(),
179 constraint.var_index().data(),
180 constraint.coefficient().data());
181 if (status == HighsStatus::kError) {
182 response.set_status(MPSOLVER_MODEL_INVALID);
183 response.set_status_str(
"ct addRow");
189 for (
int c = 0; c < model.constraint_size(); ++c) {
190 const MPConstraintProto& constraint = model.constraint(c);
191 std::string constraint_name_str =
"";
192 if (!constraint.name().empty()) {
193 constraint_name_str = constraint.name();
194 highs.passRowName(c, constraint_name_str);
199 if (!model.general_constraint().empty()) {
200 response.set_status(MPSOLVER_MODEL_INVALID);
201 response.set_status_str(
"general constraints are not supported in Highs");
206 if (model.maximize()) {
207 const ObjSense pass_sense = ObjSense::kMaximize;
208 highs.changeObjectiveSense(pass_sense);
211 if (model.objective_offset()) {
212 const double offset = model.objective_offset();
213 highs.changeObjectiveOffset(offset);
217 if (request->enable_internal_solver_output()) {
218 highs.setOptionValue(
"log_to_console",
true);
219 highs.setOptionValue(
"output_flag",
true);
221 highs.setOptionValue(
"log_to_console",
false);
222 highs.setOptionValue(
"output_flag",
false);
225 const absl::Time time_before = absl::Now();
228 HighsStatus run_status = highs.run();
229 switch (run_status) {
230 case HighsStatus::kError: {
231 response.set_status(MPSOLVER_NOT_SOLVED);
232 response.set_status_str(
"Error running HiGHS run()");
235 case HighsStatus::kWarning: {
236 response.set_status_str(
"Warning HiGHS run()");
239 case HighsStatus::kOk: {
240 HighsModelStatus model_status = highs.getModelStatus();
241 switch (model_status) {
242 case HighsModelStatus::kOptimal:
243 response.set_status(MPSOLVER_OPTIMAL);
245 case HighsModelStatus::kUnboundedOrInfeasible:
246 response.set_status_str(
247 "The model may actually be unbounded: HiGHS returned "
248 "kUnboundedOrInfeasible");
249 response.set_status(MPSOLVER_INFEASIBLE);
251 case HighsModelStatus::kInfeasible:
252 response.set_status(MPSOLVER_INFEASIBLE);
254 case HighsModelStatus::kUnbounded:
255 response.set_status(MPSOLVER_UNBOUNDED);
259 const HighsInfo& info = highs.getInfo();
260 if (info.primal_solution_status == kSolutionStatusFeasible)
261 response.set_status(MPSOLVER_FEASIBLE);
268 const absl::Duration solving_duration = absl::Now() - time_before;
270 response.mutable_solve_info()->set_solve_wall_time_seconds(
271 absl::ToDoubleSeconds(solving_duration));
272 response.mutable_solve_info()->set_solve_user_time_seconds(
275 if (response.status() == MPSOLVER_OPTIMAL) {
276 double objective_value = highs.getObjectiveValue();
277 response.set_objective_value(objective_value);
278 response.set_best_objective_bound(objective_value);
280 response.mutable_variable_value()->Resize(variable_size, 0);
281 for (
int column = 0; column < variable_size; column++) {
282 response.mutable_variable_value()->mutable_data()[column] =
283 highs.getSolution().col_value[column];
286 if (has_integer_variables) {
287 for (
int v = 0; v < variable_size; ++v) {
288 if (model.variable(v).is_integer()) {
289 response.set_variable_value(v,
290 std::round(response.variable_value(v)));
295 if (!has_integer_variables && model.general_constraint_size() == 0) {
296 response.mutable_dual_value()->Resize(model.constraint_size(), 0);
297 for (
int row = 0; row < model.constraint_size(); row++) {
298 response.set_dual_value(row, highs.getSolution().row_value[row]);