Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
xpress_proto_solver.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <cmath>
18#include <cstdint>
19#include <limits>
20#include <memory>
21#include <numeric>
22#include <string>
23#include <vector>
24
25#include "absl/base/attributes.h"
26#include "absl/cleanup/cleanup.h"
27#include "absl/log/check.h"
28#include "absl/status/status.h"
29#include "absl/status/statusor.h"
30#include "absl/strings/str_cat.h"
31#include "absl/strings/str_format.h"
32#include "absl/strings/str_join.h"
33#include "absl/strings/str_split.h"
34#include "absl/strings/string_view.h"
35#include "absl/time/clock.h"
36#include "absl/time/time.h"
37#include "absl/types/optional.h"
40#include "ortools/base/timer.h"
41#include "ortools/linear_solver/linear_solver.pb.h"
45
46namespace operations_research {
47
48// namespace {
49// constexpr int XPRS_OK = 0;
50
51// bool XPressCodeToInvalidResponse(int error_code, const char* source_file,
52// int source_line, const char* statement,
53// XPRSprob prob, MPSolutionResponse* response)
54// {
55// if (error_code == XPRS_OK) return true;
56// response->set_status();
57// response->set_status_message(absl::StrFormat(
58// "XPress error code %d (file '%s', line %d) on '%s': %s", error_code,
59// source_file, source_line, statement, XPRSgeterrormsg(prob)));
60// return false;
61// }
62
63// int AddIndicatorConstraint(const MPGeneralConstraintProto& gen_cst,
64// XPRSprob xpress_model,
65// std::vector<int>* tmp_variables,
66// std::vector<double>* tmp_coefficients) {
67// CHECK(xpress_model != nullptr);
68// CHECK(tmp_variables != nullptr);
69// CHECK(tmp_coefficients != nullptr);
70
71// const auto& ind_cst = gen_cst.indicator_constraint();
72// MPConstraintProto cst = ind_cst.constraint();
73// if (cst.lower_bound() > -std::numeric_limits<double>::infinity()) {
74// int status = XPRSaddgenconstrIndicator(
75// xpress_model, gen_cst.name().c_str(), ind_cst.var_index(),
76// ind_cst.var_value(), cst.var_index_size(),
77// cst.mutable_var_index()->mutable_data(),
78// cst.mutable_coefficient()->mutable_data(),
79// cst.upper_bound() == cst.lower_bound() ? XPRS_EQUAL
80// : XPRS_GREATER_EQUAL,
81// cst.lower_bound());
82// if (status != XPRS_OK) return status;
83// }
84// if (cst.upper_bound() < std::numeric_limits<double>::infinity() &&
85// cst.lower_bound() != cst.upper_bound()) {
86// return XPRSaddgenconstrIndicator(xpress_model, gen_cst.name().c_str(),
87// ind_cst.var_index(),
88// ind_cst.var_value(),
89// cst.var_index_size(),
90// cst.mutable_var_index()->mutable_data(),
91// cst.mutable_coefficient()->mutable_data(),
92// XPRS_LESS_EQUAL, cst.upper_bound());
93// }
94
95// return XPRS_OK;
96// }
97
98// int AddSosConstraint(const MPSosConstraint& sos_cst, XPRSprob xpress_model,
99// std::vector<int>* tmp_variables,
100// std::vector<double>* tmp_weights) {
101// CHECK(xpress_model != nullptr);
102// CHECK(tmp_variables != nullptr);
103// CHECK(tmp_weights != nullptr);
104
105// tmp_variables->resize(sos_cst.var_index_size(), 0);
106// for (int v = 0; v < sos_cst.var_index_size(); ++v) {
107// (*tmp_variables)[v] = sos_cst.var_index(v);
108// }
109// tmp_weights->resize(sos_cst.var_index_size(), 0);
110// if (sos_cst.weight_size() == sos_cst.var_index_size()) {
111// for (int w = 0; w < sos_cst.weight_size(); ++w) {
112// (*tmp_weights)[w] = sos_cst.weight(w);
113// }
114// } else {
115// DCHECK_EQ(sos_cst.weight_size(), 0);
116// // XPress requires variable weights in their SOS constraints.
117// std::iota(tmp_weights->begin(), tmp_weights->end(), 1);
118// }
119
120// std::vector<int> types = {sos_cst.type() == MPSosConstraint::SOS1_DEFAULT
121// ? XPRS_SOS_TYPE1
122// : XPRS_SOS_TYPE2};
123// std::vector<int> begins = {0};
124// return XPRSaddsos(xpress_model, /*numsos=*/1,
125// /*nummembers=*/sos_cst.var_index_size(),
126// /*types=*/types.data(),
127// /*beg=*/begins.data(), /*ind=*/tmp_variables->data(),
128// /*weight*/ tmp_weights->data());
129// }
130
131// int AddQuadraticConstraint(const MPGeneralConstraintProto& gen_cst,
132// XPRSprob xpress_model) {
133// CHECK(xpress_model != nullptr);
134// constexpr double kInfinity = std::numeric_limits<double>::infinity();
135
136// CHECK(gen_cst.has_quadratic_constraint());
137// const MPQuadraticConstraint& quad_cst = gen_cst.quadratic_constraint();
138
139// auto addqconstr = [](XPRSprob xpress_model, MPQuadraticConstraint quad_cst,
140// char sense, double rhs, const std::string& name) {
141// return XPRSaddqconstr(
142// xpress_model,
143// /*numlnz=*/quad_cst.var_index_size(),
144// /*lind=*/quad_cst.mutable_var_index()->mutable_data(),
145// /*lval=*/quad_cst.mutable_coefficient()->mutable_data(),
146// /*numqnz=*/quad_cst.qvar1_index_size(),
147// /*qrow=*/quad_cst.mutable_qvar1_index()->mutable_data(),
148// /*qcol=*/quad_cst.mutable_qvar2_index()->mutable_data(),
149// /*qval=*/quad_cst.mutable_qcoefficient()->mutable_data(),
150// /*sense=*/sense,
151// /*rhs=*/rhs,
152// /*QCname=*/name.c_str());
153// };
154
155// if (quad_cst.has_lower_bound() && quad_cst.lower_bound() > -kInfinity) {
156// const int xprs_status =
157// addqconstr(xpress_model, gen_cst.quadratic_constraint(),
158// XPRS_GREATER_EQUAL, quad_cst.lower_bound(),
159// gen_cst.has_name() ? gen_cst.name() + "_lb" : "");
160// if (xprs_status != XPRS_OK) return xprs_status;
161// }
162// if (quad_cst.has_upper_bound() && quad_cst.upper_bound() < kInfinity) {
163// const int xprs_status =
164// addqconstr(xpress_model, gen_cst.quadratic_constraint(),
165// XPRS_LESS_EQUAL, quad_cst.upper_bound(),
166// gen_cst.has_name() ? gen_cst.name() + "_ub" : "");
167// if (xprs_status != XPRS_OK) return xprs_status;
168// }
169
170// return XPRS_OK;
171// }
172
173// int AddAndConstraint(const MPGeneralConstraintProto& gen_cst,
174// XPRSprob xpress_model, std::vector<int>* tmp_variables)
175// {
176// CHECK(xpress_model != nullptr);
177// CHECK(tmp_variables != nullptr);
178
179// auto and_cst = gen_cst.and_constraint();
180// return XPRSaddgenconstrAnd(
181// xpress_model,
182// /*name=*/gen_cst.name().c_str(),
183// /*resvar=*/and_cst.resultant_var_index(),
184// /*nvars=*/and_cst.var_index_size(),
185// /*vars=*/and_cst.mutable_var_index()->mutable_data());
186// }
187
188// int AddOrConstraint(const MPGeneralConstraintProto& gen_cst,
189// XPRSprob xpress_model, std::vector<int>* tmp_variables) {
190// CHECK(xpress_model != nullptr);
191// CHECK(tmp_variables != nullptr);
192
193// auto or_cst = gen_cst.or_constraint();
194// return XPRSaddgenconstrOr(
195// xpress_model,
196// /*name=*/gen_cst.name().c_str(),
197// /*resvar=*/or_cst.resultant_var_index(),
198// /*nvars=*/or_cst.var_index_size(),
199// /*vars=*/or_cst.mutable_var_index()->mutable_data());
200// }
201
202// int AddMinConstraint(const MPGeneralConstraintProto& gen_cst,
203// XPRSprob xpress_model, std::vector<int>* tmp_variables)
204// {
205// CHECK(xpress_model != nullptr);
206// CHECK(tmp_variables != nullptr);
207
208// auto min_cst = gen_cst.min_constraint();
209// return XPRSaddgenconstrMin(
210// xpress_model,
211// /*name=*/gen_cst.name().c_str(),
212// /*resvar=*/min_cst.resultant_var_index(),
213// /*nvars=*/min_cst.var_index_size(),
214// /*vars=*/min_cst.mutable_var_index()->mutable_data(),
215// /*constant=*/min_cst.has_constant()
216// ? min_cst.constant()
217// : std::numeric_limits<double>::infinity());
218// }
219
220// int AddMaxConstraint(const MPGeneralConstraintProto& gen_cst,
221// XPRSprob xpress_model, std::vector<int>* tmp_variables)
222// {
223// CHECK(xpress_model != nullptr);
224// CHECK(tmp_variables != nullptr);
225
226// auto max_cst = gen_cst.max_constraint();
227// return XPRSaddgenconstrMax(
228// xpress_model,
229// /*name=*/gen_cst.name().c_str(),
230// /*resvar=*/max_cst.resultant_var_index(),
231// /*nvars=*/max_cst.var_index_size(),
232// /*vars=*/max_cst.mutable_var_index()->mutable_data(),
233// /*constant=*/max_cst.has_constant()
234// ? max_cst.constant()
235// : -std::numeric_limits<double>::infinity());
236// }
237// } // namespace
238
239// std::string SetSolverSpecificParameters(absl::string_view parameters,
240// XPRSprob xpress) {
241// if (parameters.empty()) return absl::OkStatus();
242// std::vector<std::string> error_messages;
243// for (absl::string_view line : absl::StrSplit(parameters, '\n')) {
244// // Empty lines are simply ignored.
245// if (line.empty()) continue;
246// // Comment tokens end at the next new-line, or the end of the string.
247// // The first character must be '#'
248// if (line[0] == '#') continue;
249// for (absl::string_view token :
250// absl::StrSplit(line, ',', absl::SkipWhitespace())) {
251// if (token.empty()) continue;
252// std::vector<std::string> key_value =
253// absl::StrSplit(token, absl::ByAnyChar(" ="),
254// absl::SkipWhitespace());
255// // If one parameter fails, we keep processing the list of parameters.
256// if (key_value.size() != 2) {
257// const std::string current_message =
258// absl::StrCat("Cannot parse parameter '", token,
259// "'. Expected format is 'ParameterName value' or "
260// "'ParameterName=value'");
261// error_messages.push_back(current_message);
262// continue;
263// }
264// const int xpress_code =
265// XPRSsetparam(xpress, key_value[0].c_str(), key_value[1].c_str());
266// if (xpress_code != XPRS_OK) {
267// const std::string current_message = absl::StrCat(
268// "Error setting parameter '", key_value[0], "' to value '",
269// key_value[1], "': ", XPRSgeterrormsg(xpress));
270// error_messages.push_back(current_message);
271// continue;
272// }
273// VLOG(2) << absl::StrCat("Set parameter '", key_value[0], "' to value
274// '",
275// key_value[1]);
276// }
277// }
278
279// if (error_messages.empty()) return "";
280// return absl::StrJoin(error_messages, "\n");
281// }
282
283MPSolutionResponse XPressSolveProto(LazyMutableCopy<MPModelRequest> request) {
284 MPSolutionResponse response;
285 response.set_status(MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
286
287 // const absl::optional<LazyMutableCopy<MPModelProto>> optional_model =
288 // ExtractValidMPModelOrPopulateResponseStatus(request, &response);
289 // if (!optional_model) return response;
290 // const MPModelProto& model = optional_model->get();
291
292 // // We set `xpress_env` to point to a new environment if no existing one
293 // is
294 // // provided. We must make sure that we free this environment when we exit
295 // this
296 // // function.
297 // bool xpress_env_was_created = false;
298 // auto xpress_env_deleter = absl::MakeCleanup([&]() {
299 // if (xpress_env_was_created && xpress_env != nullptr) {
300 // XPRSfreeenv(xpress_env);
301 // }
302 // });
303 // if (xpress_env == nullptr) {
304 // ASSIGN_OR_RETURN(xpress_env, GetXPressEnv());
305 // xpress_env_was_created = true;
306 // }
307
308 // XPRSprob xpress_model = nullptr;
309 // auto xpress_model_deleter = absl::MakeCleanup([&]() {
310 // const int error_code = XPRSfreemodel(xpress_model);
311 // LOG_IF(DFATAL, error_code != XPRS_OK)
312 // << "XPRSfreemodel failed with error " << error_code << ": "
313 // << XPRSgeterrormsg(xpress_env);
314 // });
315
316 // // `xpress_env` references ther XPRSenv argument.
317 // #define RETURN_IF_XPRESS_ERROR(x) \
318// RETURN_IF_ERROR( \
319// if (!XPressCodeToInvalidResponse(x, __FILE__, __LINE__, #x, xpress,
320 // &response)) { \
321// return response; \
322// })
323
324 // RETURN_IF_XPRESS_ERROR(XPRSnewmodel(xpress_env, &xpress_model,
325 // model.name().c_str(),
326 // /*numvars=*/0,
327 // /*obj=*/nullptr,
328 // /*lb=*/nullptr,
329 // /*ub=*/nullptr,
330 // /*vtype=*/nullptr,
331 // /*varnames=*/nullptr));
332 // XPRSprob const model_env = XPRSgetenv(xpress_model);
333
334 // if (request.has_solver_specific_parameters()) {
335 // const auto parameters_status = SetSolverSpecificParameters(
336 // request.solver_specific_parameters(), model_env);
337 // if (!parameters_status.ok()) {
338 // response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
339 // response.set_status_str(
340 // std::string(parameters_status.message())); // NOLINT
341 // return response;
342 // }
343 // }
344 // if (request.solver_time_limit_seconds() > 0) {
345 // RETURN_IF_XPRESS_ERROR(
346 // XPRSsetdblparam(model_env, XPRS_DBL_PAR_TIMELIMIT,
347 // request.solver_time_limit_seconds()));
348 // }
349 // RETURN_IF_XPRESS_ERROR(
350 // XPRSsetintparam(model_env, XPRS_INT_PAR_OUTPUTFLAG,
351 // request.enable_internal_solver_output()));
352
353 // const int variable_size = model.variable_size();
354 // bool has_integer_variables = false;
355 // {
356 // std::vector<double> obj_coeffs(variable_size, 0);
357 // std::vector<double> lb(variable_size);
358 // std::vector<double> ub(variable_size);
359 // std::vector<char> ctype(variable_size);
360 // std::vector<const char*> varnames(variable_size);
361 // for (int v = 0; v < variable_size; ++v) {
362 // const MPVariableProto& variable = model.variable(v);
363 // obj_coeffs[v] = variable.objective_coefficient();
364 // lb[v] = variable.lower_bound();
365 // ub[v] = variable.upper_bound();
366 // ctype[v] = variable.is_integer() &&
367 // request.solver_type() ==SolutionRes
368 // : XPRS_CONTINUOUS;
369 // if (variable.is_integer()) has_integer_variables = true;
370 // if (!variable.name().empty()) varnames[v] = variable.name().c_str();
371 // }
372
373 // RETURN_IF_XPRESS_ERROR(
374 // XPRSaddvars(xpress_model, variable_size, 0, nullptr, nullptr,
375 // nullptr,
376 // /*obj=*/obj_coeffs.data(),
377 // /*lb=*/lb.data(), /*ub=*/ub.data(),
378 // /*vtype=*/ctype.data(),
379 // /*varnames=*/const_cast<char**>(varnames.data())));
380
381 // // Set solution hints if any.
382 // for (int i = 0; i < model.solution_hint().var_index_size(); ++i) {
383 // RETURN_IF_XPRESS_ERROR(XPRSsetdblattrelement(
384 // xpress_model, XPRS_DBL_ATTR_START, model.solution_hint().var_inde
385 // const absl::optional<LazyMutableCopy<MPModelProto>>
386 // optional_model =
387 // ExtractValidMPModelOrPopulateResponseStatus(request, &response);
388 // if (!optional_model) return response;
389 // const MPModelProto& model = optional_model->get();
390
391 // // We set `xpress_env` to point to a new environment if no existing one
392 // is
393 // // provided. We must make sure that we free this environment when we exit
394 // this
395 // // function.
396 // bool xpress_env_was_created = false;
397 // auto xpress_env_deleter = absl::MakeCleanup([&]() {
398 // if (xpress_env_was_created && xpress_env != nullptr) {
399 // XPRSfreeenv(xpress_env);
400 // }
401 // });
402 // if (xpress_env == nullptr) {
403 // ASSIGN_OR_RETURN(xpress_env, GetXPressEnv());
404 // xpress_env_was_created = true;
405 // }
406
407 // XPRSprob xpress_model = nullptr;
408 // auto xpress_model_deleter = absl::MakeCleanup([&]() {
409 // const int error_code = XPRSfreemodel(xpress_model);
410 // LOG_IF(DFATAL, error_code != XPRS_OK)
411 // << "XPRSfreemodel failed with error " << error_code << ": "
412 // << XPRSgeterrormsg(xpress_env);
413 // });
414
415 // // `xpress_env` references ther XPRSenv argument.
416 // #define RETURN_IF_XPRESS_ERROR(x) \
417// RETURN_IF_ERROR( \
418// XPressCodeToUtilStatus(x, __FILE__, __LINE__, #x, xpress_env));
419
420 // RETURN_IF_XPRESS_ERROR(XPRSnewmodel(xpress_env, &xpress_model,
421 // model.name().c_str(),
422 // /*numvars=*/0,
423 // /*obj=*/nullptr,
424 // /*lb=*/nullptr,
425 // /*ub=*/nullptr,
426 // /*vtype=*/nullptr,
427 // /*varnames=*/nullptr));
428 // XPRSprob const model_env = XPRSgetenv(xpress_model);
429
430 // if (request.has_solver_specific_parameters()) {
431 // const auto parameters_status = SetSolverSpecificParameters(
432 // request.solver_specific_parameters(), model_env);
433 // if (!parameters_status.ok()) {
434 // response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
435 // response.set_status_str(
436 // std::string(parameters_status.message())); // NOLINT
437 // return response;
438 // }
439 // }
440 // if (request.solver_time_limit_seconds() > 0) {
441 // RETURN_IF_XPRESS_ERROR(
442 // XPRSsetdblparam(model_env, XPRS_DBL_PAR_TIMELIMIT,
443 // request.solver_time_limit_seconds()));
444 // }
445 // RETURN_IF_XPRESS_ERROR(
446 // XPRSsetintparam(model_env, XPRS_INT_PAR_OUTPUTFLAG,
447 // request.enable_internal_solver_output()));
448
449 // const int variable_size = model.variable_size();
450 // bool has_integer_variables = false;
451 // {
452 // std::vector<double> obj_coeffs(variable_size, 0);
453 // std::vector<double> lb(variable_size);
454 // std::vector<double> ub(variable_size);
455 // std::vector<char> ctype(variable_size);
456 // std::vector<const char*> varnames(variable_size);
457 // for (int v = 0; v < variable_size; ++v) {
458 // const MPVariableProto& variable = model.variable(v);
459 // obj_coeffs[v] = variable.objective_coefficient();
460 // lb[v] = variable.lower_bound();
461 // ub[v] = variable.upper_bound();
462 // ctype[v] = variable.is_integer() &&
463 // request.solver_type() ==
464 // MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING
465 // ? XPRS_INTEGER
466 // : XPRS_CONTINUOUS;
467 // if (variable.is_integer()) has_integer_variables = true;
468 // if (!variable.name().empty()) varnames[v] = variable.name().c_str();
469 // }
470
471 // RETURN_IF_XPRESS_ERROR(
472 // XPRSaddvars(xpress_model, variable_size, 0, nullptr, nullptr,
473 // nullptr,
474 // /*obj=*/obj_coeffs.data(),
475 // /*lb=*/lb.data(), /*ub=*/ub.data(),
476 // /*vtype=*/ctype.data(),
477 // /*varnames=*/const_cast<char**>(varnames.data())));
478
479 // // Set solution hints if any.
480 // for (int i = 0; i < model.solution_hint().var_index_size(); ++i) {
481 // RETURN_IF_XPRESS_ERROR(XPRSsetdblattrelement(
482 // xpress_model, XPRS_DBL_ATTR_START,
483 // model.solution_hint().var_index(i),
484 // model.solution_hint().var_value(i)));
485 // }
486 // }
487
488 // {
489 // std::vector<int> ct_variables;
490 // std::vector<double> ct_coefficients;
491 // for (int c = 0; c < model.constraint_size(); ++c) {
492 // const MPConstraintProto& constraint = model.constraint(c);
493 // const int size = constraint.var_index_size();
494 // ct_variables.resize(size, 0);
495 // ct_coefficients.resize(size, 0);
496 // for (int i = 0; i < size; ++i) {
497 // ct_variables[i] = constraint.var_index(i);
498 // ct_coefficients[i] = constraint.coefficient(i);
499 // }
500 // // Using XPRSaddrangeconstr for constraints that don't require it
501 // adds
502 // // a slack which is not always removed by presolve.
503 // if (constraint.lower_bound() == constraint.upper_bound()) {
504 // RETURN_IF_XPRESS_ERROR(XPRSaddconstr(
505 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
506 // /*cval=*/ct_coefficients.data(),
507 // /*sense=*/XPRS_EQUAL, /*rhs=*/constraint.lower_bound(),
508 // /*constrname=*/constraint.name().c_str()));
509 // } else if (constraint.lower_bound() ==
510 // -std::numeric_limits<double>::infinity()) {
511 // RETURN_IF_XPRESS_ERROR(XPRSaddconstr(
512 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
513 // /*cval=*/ct_coefficients.data(),
514 // /*sense=*/XPRS_LESS_EQUAL, /*rhs=*/constraint.upper_bound(),
515 // /*constrname=*/constraint.name().c_str()));
516 // } else if (constraint.upper_bound() ==
517 // std::numeric_limits<double>::infinity()) {
518 // RETURN_IF_XPRESS_ERROR(XPRSaddconstr(
519 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
520 // /*cval=*/ct_coefficients.data(),
521 // /*sense=*/XPRS_GREATER_EQUAL, /*rhs=*/constraint.lower_bound(),
522 // /*constrname=*/constraint.name().c_str()));
523 // } else {
524 // RETURN_IF_XPRESS_ERROR(XPRSaddrangeconstr(
525 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
526 // /*cval=*/ct_coefficients.data(),
527 // /*lower=*/constraint.lower_bound(),
528 // /*upper=*/constraint.upper_bound(),
529 // /*constrname=*/constraint.name().c_str()));
530 // }
531 // }
532
533 // for (const auto& gen_cst : model.general_constraint()) {
534 // switch (gen_cst.general_constraint_case()) {
535 // case MPGeneralConstraintProto::kIndicatorConstraint: {
536 // RETURN_IF_XPRESS_ERROR(AddIndicatorConstraint(
537 // gen_cst, xpress_model, &ct_variables, &ct_coefficients));
538 // break;
539 // }
540 // case MPGeneralConstraintProto::kSosConstraint: {
541 // RETURN_IF_XPRESS_ERROR(AddSosConstraint(gen_cst.sos_constraint(),
542 // xpress_model,
543 // &ct_variables,
544 // &ct_coefficients));
545 // break;
546 // }
547 // case MPGeneralConstraintProto::kQuadraticConstraint: {
548 // RETURN_IF_XPRESS_ERROR(AddQuadraticConstraint(gen_cst,
549 // xpress_model)); break;
550 // }
551 // case MPGeneralConstraintProto::kAbsConstraint: {
552 // RETURN_IF_XPRESS_ERROR(XPRSaddgenconstrAbs(
553 // xpress_model,
554 // /*name=*/gen_cst.name().c_str(),
555 // /*resvar=*/gen_cst.abs_constraint().resultant_var_index(),
556 // /*argvar=*/gen_cst.abs_constraint().var_index()));
557 // break;
558 // }
559 // case MPGeneralConstraintProto::kAndConstraint: {
560 // RETURN_IF_XPRESS_ERROR(
561 // AddAndConstraint(gen_cst, xpress_model, &ct_variables));
562 // break;
563 // }
564 // case MPGeneralConstraintProto::kOrConstraint: {
565 // RETURN_IF_XPRESS_ERROR(
566 // AddOrConstraint(gen_cst, xpress_model, &ct_variables));
567 // break;
568 // }
569 // case MPGeneralConstraintProto::kMinConstraint: {
570 // RETURN_IF_XPRESS_ERROR(
571 // AddMinConstraint(gen_cst, xpress_model, &ct_variables));
572 // break;
573 // }
574 // case MPGeneralConstraintProto::kMaxConstraint: {
575 // RETURN_IF_XPRESS_ERROR(
576 // AddMaxConstraint(gen_cst, xpress_model, &ct_variables));
577 // break;
578 // }
579 // default:
580 // return absl::UnimplementedError(
581 // absl::StrFormat("General constraints of type %i not
582 // supported.",
583 // gen_cst.general_constraint_case()));
584 // }
585 // }
586 // }
587
588 // RETURN_IF_XPRESS_ERROR(XPRSsetintattr(xpress_model,
589 // XPRS_INT_ATTR_MODELSENSE,
590 // model.maximize() ? -1 : 1));
591 // RETURN_IF_XPRESS_ERROR(XPRSsetdblattr(xpress_model, XPRS_DBL_ATTR_OBJCON,
592 // model.objective_offset()));
593 // if (model.has_quadratic_objective()) {
594 // MPQuadraticObjective qobj = model.quadratic_objective();
595 // if (qobj.coefficient_size() > 0) {
596 // RETURN_IF_XPRESS_ERROR(
597 // XPRSaddqpterms(xpress_model, /*numqnz=*/qobj.coefficient_size(),
598 // /*qrow=*/qobj.mutable_qvar1_index()->mutable_data(),
599 // /*qcol=*/qobj.mutable_qvar2_index()->mutable_data(),
600 // /*qval=*/qobj.mutable_coefficient()->mutable_data()));
601 // }
602 // }
603
604 // RETURN_IF_XPRESS_ERROR(XPRSupdatemodel(xpress_model));
605
606 // const absl::Time time_before = absl::Now();
607 // UserTimer user_timer;
608 // user_timer.Start();
609
610 // RETURN_IF_XPRESS_ERROR(XPRSoptimize(xpress_model));
611
612 // const absl::Duration solving_duration = absl::Now() - time_before;
613 // user_timer.Stop();
614 // VLOG(1) << "Finished solving in XPressSolveProto(), walltime = "
615 // << solving_duration << ", usertime = " <<
616 // user_timer.GetDuration();
617 // response.mutable_solve_info()->set_solve_wall_time_seconds(
618 // absl::ToDoubleSeconds(solving_duration));
619 // response.mutable_solve_info()->set_solve_user_time_seconds(
620 // absl::ToDoubleSeconds(user_timer.GetDuration()));
621
622 // int optimization_status = 0;
623 // RETURN_IF_XPRESS_ERROR(
624 // XPRSgetintattr(xpress_model, XPRS_INT_ATTR_STATUS,
625 // &optimization_status));
626 // int solution_count = 0;
627 // RETURN_IF_XPRESS_ERROR(
628 // XPRSgetintattr(xpress_model, XPRS_INT_ATTR_SOLCOUNT,
629 // &solution_count));
630 // switch (optimization_status) {
631 // case XPRS_OPTIMAL:
632 // response.set_status(MPSOLVER_OPTIMAL);
633 // break;
634 // case XPRS_INF_OR_UNBD:
635 // DLOG(INFO) << "XPress solve returned XPRS_INF_OR_UNBD, which we treat
636 // as "
637 // "INFEASIBLE even though it may mean UNBOUNDED.";
638 // response.set_status_str(
639 // "The model may actually be unbounded: XPress returned "
640 // "XPRS_INF_OR_UNBD");
641 // ABSL_FALLTHROUGH_INTENDED;
642 // case XPRS_INFEASIBLE:
643 // response.set_status(MPSOLVER_INFEASIBLE);
644 // break;
645 // case XPRS_UNBOUNDED:
646 // response.set_status(MPSOLVER_UNBOUNDED);
647 // break;
648 // default: {
649 // if (solution_count > 0) {
650 // response.set_status(MPSOLVER_FEASIBLE);
651 // } else {
652 // response.set_status(MPSOLVER_NOT_SOLVED);
653 // response.set_status_str(
654 // absl::StrFormat("XPress status code %d", optimization_status));
655 // }
656 // break;
657 // }
658 // }
659
660 // if (solution_count > 0 && (response.status() == MPSOLVER_FEASIBLE ||
661 // response.status() == MPSOLVER_OPTIMAL)) {
662 // double objective_value = 0;
663 // RETURN_IF_XPRESS_ERROR(
664 // XPRSgetdblattr(xpress_model, XPRS_DBL_ATTR_OBJVAL,
665 // &objective_value));
666 // response.set_objective_value(objective_value);
667 // double best_objective_bound = 0;
668 // const int error = XPRSgetdblattr(xpress_model, XPRS_DBL_ATTR_OBJBOUND,
669 // &best_objective_bound);
670 // if (response.status() == MPSOLVER_OPTIMAL &&
671 // error == XPRS_ERROR_DATA_NOT_AVAILABLE) {
672 // // If the presolve deletes all variables, there's no best bound.
673 // response.set_best_objective_bound(objective_value);
674 // } else {
675 // RETURN_IF_XPRESS_ERROR(error);
676 // response.set_best_objective_bound(best_objective_bound);
677 // }
678
679 // response.mutable_variable_value()->Resize(variable_size, 0);
680 // RETURN_IF_XPRESS_ERROR(
681 // XPRSgetdblattrarray(xpress_model, XPRS_DBL_ATTR_X, 0,
682 // variable_size,
683 // response.mutable_variable_value()->mutable_data()));
684 // // NOTE, XPressSolveProto() is exposed to external clients via MPSolver
685 // API,
686 // // which assumes the solution values of integer variables are rounded
687 // to
688 // // integer values.
689 // auto round_values_of_integer_variables_fn =
690 // [&](google::protobuf::RepeatedField<double>* values) {
691 // for (int v = 0; v < variable_size; ++v) {
692 // if (model.variable(v).is_integer()) {
693 // (*values)[v] = std::round((*values)[v]);
694 // }
695 // }
696 // };
697 // round_values_of_integer_variables_fn(response.mutable_variable_value());
698 // if (!has_integer_variables && model.general_constraint_size() == 0) {
699 // response.mutable_dual_value()->Resize(model.constraint_size(), 0);
700 // RETURN_IF_XPRESS_ERROR(XPRSgetdblattrarray(
701 // xpress_model, XPRS_DBL_ATTR_PI, 0, model.constraint_size(),
702 // response.mutable_dual_value()->mutable_data()));
703 // }
704 // const int additional_solutions = std::min(
705 // solution_count,
706 // std::min(request.populate_additional_solutions_up_to(),
707 // std::numeric_limits<int32_t>::max() - 1) +
708 // 1);
709 // for (int i = 1; i < additional_solutions; ++i) {
710 // RETURN_IF_XPRESS_ERROR(
711 // XPRSsetintparam(model_env, XPRS_INT_PAR_SOLUTIONNUMBER, i));
712 // MPSolution* solution = response.add_additional_solutions();
713 // solution->mutable_variable_value()->Resize(variable_size, 0);
714 // double objective_value = 0;
715 // RETURN_IF_XPRESS_ERROR(XPRSgetdblattr(
716 // xpress_model, XPRS_DBL_ATTR_POOLOBJVAL, &objective_value));
717 // solution->set_objective_value(objective_value);
718 // RETURN_IF_XPRESS_ERROR(XPRSgetdblattrarray(
719 // xpress_model, XPRS_DBL_ATTR_XN, 0, variable_size,
720 // solution->mutable_variable_value()->mutable_data()));
721 // round_values_of_integer_variables_fn(solution->mutable_variable_value());
722 // }
723 // }
724 // #undef RETURN_IF_XPRESS_ERRORx(i),
725 // model.solution_hint().var_value(i)));
726 // }
727 // }
728
729 // {
730 // std::vector<int> ct_variables;
731 // std::vector<double> ct_coefficients;
732 // for (int c = 0; c < model.constraint_size(); ++c) {
733 // const MPConstraintProto& constraint = model.constraint(c);
734 // const int size = constraint.var_index_size();
735 // ct_variables.resize(size, 0);
736 // ct_coefficients.resize(size, 0);
737 // for (int i = 0; i < size; ++i) {
738 // ct_variables[i] = constraint.var_index(i);
739 // ct_coefficients[i] = constraint.coefficient(i);
740 // }
741 // // Using XPRSaddrangeconstr for constraints that don't require it
742 // adds
743 // // a slack which is not always removed by presolve.
744 // if (constraint.lower_bound() == constraint.upper_bound()) {
745 // RETURN_IF_XPRESS_ERROR(XPRSaddconstr(
746 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
747 // /*cval=*/ct_coefficients.data(),
748 // /*sense=*/XPRS_EQUAL, /*rhs=*/constraint.lower_bound(),
749 // /*constrname=*/constraint.name().c_str()));
750 // } else if (constraint.lower_bound() ==
751 // -std::numeric_limits<double>::infinity()) {
752 // RETURN_IF_XPRESS_ERROR(XPRSaddconstr(
753 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
754 // /*cval=*/ct_coefficients.data(),
755 // /*sense=*/XPRS_LESS_EQUAL, /*rhs=*/constraint.upper_bound(),
756 // /*constrname=*/constraint.name().c_str()));
757 // } else if (constraint.upper_bound() ==
758 // std::numeric_limits<double>::infinity()) {
759 // RETURN_IF_XPRESS_ERROR(XPRSaddconstr(
760 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
761 // /*cval=*/ct_coefficients.data(),
762 // /*sense=*/XPRS_GREATER_EQUAL, /*rhs=*/constraint.lower_bound(),
763 // /*constrname=*/constraint.name().c_str()));
764 // } else {
765 // RETURN_IF_XPRESS_ERROR(XPRSaddrangeconstr(
766 // xpress_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
767 // /*cval=*/ct_coefficients.data(),
768 // /*lower=*/constraint.lower_bound(),
769 // /*upper=*/constraint.upper_bound(),
770 // /*constrname=*/constraint.name().c_str()));
771 // }
772 // }
773
774 // for (const auto& gen_cst : model.general_constraint()) {
775 // switch (gen_cst.general_constraint_case()) {
776 // case MPGeneralConstraintProto::kIndicatorConstraint: {
777 // RETURN_IF_XPRESS_ERROR(AddIndicatorConstraint(
778 // gen_cst, xpress_model, &ct_variables, &ct_coefficients));
779 // break;
780 // }
781 // case MPGeneralConstraintProto::kSosConstraint: {
782 // RETURN_IF_XPRESS_ERROR(AddSosConstraint(gen_cst.sos_constraint(),
783 // xpress_model,
784 // &ct_variables,
785 // &ct_coefficients));
786 // break;
787 // }
788 // case MPGeneralConstraintProto::kQuadraticConstraint: {
789 // RETURN_IF_XPRESS_ERROR(AddQuadraticConstraint(gen_cst,
790 // xpress_model)); break;
791 // }
792 // case MPGeneralConstraintProto::kAbsConstraint: {
793 // RETURN_IF_XPRESS_ERROR(XPRSaddgenconstrAbs(
794 // xpress_model,
795 // /*name=*/gen_cst.name().c_str(),
796 // /*resvar=*/gen_cst.abs_constraint().resultant_var_index(),
797 // /*argvar=*/gen_cst.abs_constraint().var_index()));
798 // break;
799 // }
800 // case MPGeneralConstraintProto::kAndConstraint: {
801 // RETURN_IF_XPRESS_ERROR(
802 // AddAndConstraint(gen_cst, xpress_model, &ct_variables));
803 // break;
804 // }
805 // case MPGeneralConstraintProto::kOrConstraint: {
806 // RETURN_IF_XPRESS_ERROR(
807 // AddOrConstraint(gen_cst, xpress_model, &ct_variables));
808 // break;
809 // }
810 // case MPGeneralConstraintProto::kMinConstraint: {
811 // RETURN_IF_XPRESS_ERROR(
812 // AddMinConstraint(gen_cst, xpress_model, &ct_variables));
813 // break;
814 // }
815 // case MPGeneralConstraintProto::kMaxConstraint: {
816 // RETURN_IF_XPRESS_ERROR(
817 // AddMaxConstraint(gen_cst, xpress_model, &ct_variables));
818 // break;
819 // }
820 // default:
821 // return absl::UnimplementedError(
822 // absl::StrFormat("General constraints of type %i not
823 // supported.",
824 // gen_cst.general_constraint_case()));
825 // }
826 // }
827 // }
828
829 // RETURN_IF_XPRESS_ERROR(XPRSsetintattr(xpress_model,
830 // XPRS_INT_ATTR_MODELSENSE,
831 // model.maximize() ? -1 : 1));
832 // RETURN_IF_XPRESS_ERROR(XPRSsetdblattr(xpress_model, XPRS_DBL_ATTR_OBJCON,
833 // model.objective_offset()));
834 // if (model.has_quadratic_objective()) {
835 // MPQuadraticObjective qobj = model.quadratic_objective();
836 // if (qobj.coefficient_size() > 0) {
837 // RETURN_IF_XPRESS_ERROR(
838 // XPRSaddqpterms(xpress_model, /*numqnz=*/qobj.coefficient_size(),
839 // /*qrow=*/qobj.mutable_qvar1_index()->mutable_data(),
840 // /*qcol=*/qobj.mutable_qvar2_index()->mutable_data(),
841 // /*qval=*/qobj.mutable_coefficient()->mutable_data()));
842 // }
843 // }
844
845 // RETURN_IF_XPRESS_ERROR(XPRSupdatemodel(xpress_model));
846
847 // const absl::Time time_before = absl::Now();
848 // UserTimer user_timer;
849 // user_timer.Start();
850
851 // RETURN_IF_XPRESS_ERROR(XPRSoptimize(xpress_model));
852
853 // const absl::Duration solving_duration = absl::Now() - time_before;
854 // user_timer.Stop();
855 // VLOG(1) << "Finished solving in XPressSolveProto(), walltime = "
856 // << solving_duration << ", usertime = " <<
857 // user_timer.GetDuration();
858 // response.mutable_solve_info()->set_solve_wall_time_seconds(
859 // absl::ToDoubleSeconds(solving_duration));
860 // response.mutable_solve_info()->set_solve_user_time_seconds(
861 // absl::ToDoubleSeconds(user_timer.GetDuration()));
862
863 // int optimization_status = 0;
864 // RETURN_IF_XPRESS_ERROR(
865 // XPRSgetintattr(xpress_model, XPRS_INT_ATTR_STATUS,
866 // &optimization_status));
867 // int solution_count = 0;
868 // RETURN_IF_XPRESS_ERROR(
869 // XPRSgetintattr(xpress_model, XPRS_INT_ATTR_SOLCOUNT,
870 // &solution_count));
871 // switch (optimization_status) {
872 // case XPRS_OPTIMAL:
873 // response.set_status(MPSOLVER_OPTIMAL);
874 // break;
875 // case XPRS_INF_OR_UNBD:
876 // DLOG(INFO) << "XPress solve returned XPRS_INF_OR_UNBD, which we treat
877 // as "
878 // "INFEASIBLE even though it may mean UNBOUNDED.";
879 // response.set_status_str(
880 // "The model may actually be unbounded: XPress returned "
881 // "XPRS_INF_OR_UNBD");
882 // ABSL_FALLTHROUGH_INTENDED;
883 // case XPRS_INFEASIBLE:
884 // response.set_status(MPSOLVER_INFEASIBLE);
885 // break;
886 // case XPRS_UNBOUNDED:
887 // response.set_status(MPSOLVER_UNBOUNDED);
888 // break;
889 // default: {
890 // if (solution_count > 0) {
891 // response.set_status(MPSOLVER_FEASIBLE);
892 // } else {
893 // response.set_status(MPSOLVER_NOT_SOLVED);
894 // response.set_status_str(
895 // absl::StrFormat("XPress status code %d", optimization_status));
896 // }
897 // break;
898 // }
899 // }
900
901 // if (solution_count > 0 && (response.status() == MPSOLVER_FEASIBLE ||
902 // response.status() == MPSOLVER_OPTIMAL)) {
903 // double objective_value = 0;
904 // RETURN_IF_XPRESS_ERROR(
905 // XPRSgetdblattr(xpress_model, XPRS_DBL_ATTR_OBJVAL,
906 // &objective_value));
907 // response.set_objective_value(objective_value);
908 // double best_objective_bound = 0;
909 // const int error = XPRSgetdblattr(xpress_model, XPRS_DBL_ATTR_OBJBOUND,
910 // &best_objective_bound);
911 // if (response.status() == MPSOLVER_OPTIMAL &&
912 // error == XPRS_ERROR_DATA_NOT_AVAILABLE) {
913 // // If the presolve deletes all variables, there's no best bound.
914 // response.set_best_objective_bound(objective_value);
915 // } else {
916 // RETURN_IF_XPRESS_ERROR(error);
917 // response.set_best_objective_bound(best_objective_bound);
918 // }
919
920 // response.mutable_variable_value()->Resize(variable_size, 0);
921 // RETURN_IF_XPRESS_ERROR(
922 // XPRSgetdblattrarray(xpress_model, XPRS_DBL_ATTR_X, 0,
923 // variable_size,
924 // response.mutable_variable_value()->mutable_data()));
925 // // NOTE, XPressSolveProto() is exposed to external clients via MPSolver
926 // API,
927 // // which assumes the solution values of integer variables are rounded
928 // to
929 // // integer values.
930 // auto round_values_of_integer_variables_fn =
931 // [&](google::protobuf::RepeatedField<double>* values) {
932 // for (int v = 0; v < variable_size; ++v) {
933 // if (model.variable(v).is_integer()) {
934 // (*values)[v] = std::round((*values)[v]);
935 // }
936 // }
937 // };
938 // round_values_of_integer_variables_fn(response.mutable_variable_value());
939 // if (!has_integer_variables && model.general_constraint_size() == 0) {
940 // response.mutable_dual_value()->Resize(model.constraint_size(), 0);
941 // RETURN_IF_XPRESS_ERROR(XPRSgetdblattrarray(
942 // xpress_model, XPRS_DBL_ATTR_PI, 0, model.constraint_size(),
943 // response.mutable_dual_value()->mutable_data()));
944 // }
945 // const int additional_solutions = std::min(
946 // solution_count,
947 // std::min(request.populate_additional_solutions_up_to(),
948 // std::numeric_limits<int32_t>::max() - 1) +
949 // 1);
950 // for (int i = 1; i < additional_solutions; ++i) {
951 // RETURN_IF_XPRESS_ERROR(
952 // XPRSsetintparam(model_env, XPRS_INT_PAR_SOLUTIONNUMBER, i));
953 // MPSolution* solution = response.add_additional_solutions();
954 // solution->mutable_variable_value()->Resize(variable_size, 0);
955 // double objective_value = 0;
956 // RETURN_IF_XPRESS_ERROR(XPRSgetdblattr(
957 // xpress_model, XPRS_DBL_ATTR_POOLOBJVAL, &objective_value));
958 // solution->set_objective_value(objective_value);
959 // RETURN_IF_XPRESS_ERROR(XPRSgetdblattrarray(
960 // xpress_model, XPRS_DBL_ATTR_XN, 0, variable_size,
961 // solution->mutable_variable_value()->mutable_data()));
962 // round_values_of_integer_variables_fn(solution->mutable_variable_value());
963 // }
964 // }
965 // #undef RETURN_IF_XPRESS_ERROR
966
967 return response;
968}
969
970} // namespace operations_research
In SWIG mode, we don't want anything besides these top-level includes.
MPSolutionResponse XPressSolveProto(LazyMutableCopy< MPModelRequest > request)
Solves the input request.