OR-Tools  9.6
glpk_solver.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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 
14 #ifndef OR_TOOLS_MATH_OPT_SOLVERS_GLPK_SOLVER_H_
15 #define OR_TOOLS_MATH_OPT_SOLVERS_GLPK_SOLVER_H_
16 
17 #include <cstdint>
18 #include <memory>
19 #include <optional>
20 #include <thread>
21 #include <vector>
22 
23 #include "absl/container/flat_hash_map.h"
24 #include "absl/status/status.h"
25 #include "absl/status/statusor.h"
26 #include "ortools/base/logging.h"
27 #include "ortools/math_opt/callback.pb.h"
30 #include "ortools/math_opt/model.pb.h"
31 #include "ortools/math_opt/model_parameters.pb.h"
32 #include "ortools/math_opt/model_update.pb.h"
33 #include "ortools/math_opt/parameters.pb.h"
34 #include "ortools/math_opt/result.pb.h"
35 
36 extern "C" {
37 #include <glpk.h>
38 }
39 
40 namespace operations_research {
41 namespace math_opt {
42 
43 class GlpkSolver : public SolverInterface {
44  public:
45  static absl::StatusOr<std::unique_ptr<SolverInterface>> New(
46  const ModelProto& model, const InitArgs& init_args);
47 
48  ~GlpkSolver() override;
49 
50  absl::StatusOr<SolveResultProto> Solve(
51  const SolveParametersProto& parameters,
52  const ModelSolveParametersProto& model_parameters,
53  MessageCallback message_cb,
54  const CallbackRegistrationProto& callback_registration, Callback cb,
55  SolveInterrupter* interrupter) override;
56  absl::StatusOr<bool> Update(const ModelUpdateProto& model_update) override;
57 
58  private:
59  // The columns of the GPLK problem.
60  //
61  // This structures is intentionally similar to LinearConstraints so that some
62  // template function can accept either of those to share code between rows and
63  // columns. For this purpose it also defines some aliases to some GLPK
64  // functions and the IsInteger() (which is trivially implemented for
65  // LinearConstraints).
66  struct Variables {
67  static constexpr auto kSetBounds = glp_set_col_bnds;
68  static constexpr auto kGetLb = glp_get_col_lb;
69  static constexpr auto kGetUb = glp_get_col_ub;
70  static constexpr auto kGetType = glp_get_col_type;
71  static constexpr auto kDelElts = glp_del_cols;
72 
73  // Returns true if the given one-based column is an integer variable.
74  static inline bool IsInteger(glp_prob* const problem, const int j);
75 
76  // The MathOpt variable id of each column in GLPK. This is zero-based, the
77  // first column corresponds to the 0 and the ids.size() matches the number
78  // of columns.
79  //
80  // The id_to_index map can be used to get the GLPK column index of a given
81  // MathOpt variable id but the return value will be one-based (the
82  // convention used in GLPK). Thus this invariant holds:
83  //
84  // for all i in [0, num_cols), id_to_index.at(ids[i]) == i + 1
85  std::vector<int64_t> ids;
86 
87  // Map each MathOpt variable id to the column one-based index in GLPK (thus
88  // values are in [1, num_cols]). See the ids vector for the counter part.
89  absl::flat_hash_map<int64_t, int> id_to_index;
90 
91  // The unrounded lower bound value of each column.
92  //
93  // We keep this value since GLPK's glp_intopt() expects integer bounds for
94  // integer variables. We need the unrounded value when the type of a
95  // variable is changed to continuous though by an update.
96  std::vector<double> unrounded_lower_bounds;
97 
98  // The unrounded upper bound value of each column.
99  //
100  // See unrounded_lower_bounds documentation for details..
101  std::vector<double> unrounded_upper_bounds;
102  };
103 
104  // The columns of the GPLK problem.
105  //
106  // See the comment on Variables for details.
107  struct LinearConstraints {
108  static constexpr auto kSetBounds = glp_set_row_bnds;
109  static constexpr auto kGetLb = glp_get_row_lb;
110  static constexpr auto kGetUb = glp_get_row_ub;
111  static constexpr auto kGetType = glp_get_row_type;
112  static constexpr auto kDelElts = glp_del_rows;
113 
114  // Returns false. This function mirrors Variables::IsInteger() and enables
115  // sharing code between variables and constraints.
116  static bool IsInteger(glp_prob*, int) { return false; }
117 
118  // The MathOpt linear constraint id of each row in GLPK. This is zero-based,
119  // the first row corresponds to the 0 and ids.size() matches the number of
120  // rows.
121  //
122  // The id_to_index map can be used to get the GLPK row index of a given
123  // MathOpt variable id but the return value will be one-based (the
124  // convention used in GLPK). Thus this invariant holds:
125  //
126  // for all i in [0, num_rows), id_to_index.at(ids[i]) == i + 1
127  std::vector<int64_t> ids;
128 
129  // Map each MathOpt linear constraint id to the row one-based index in GLPK
130  // (thus values are in [1, num_rows]). See the ids vector for the counter
131  // part.
132  absl::flat_hash_map<int64_t, int> id_to_index;
133  };
134 
135  explicit GlpkSolver(const ModelProto& model);
136 
137  // Appends the variables to GLPK cols.
138  void AddVariables(const VariablesProto& new_variables);
139 
140  // Appends the variables to GLPK rows.
141  void AddLinearConstraints(
142  const LinearConstraintsProto& new_linear_constraints);
143 
144  // Updates the objective coefficients with the new values in
145  // coefficients_proto.
146  void UpdateObjectiveCoefficients(
147  const SparseDoubleVectorProto& coefficients_proto);
148 
149  // Updates the constraints matrix with the new values in matrix_updates.
150  //
151  // The first_new_(var|cstr)_id are the smallest ids of the new
152  // variables/constraints (in MathOpt the same id is never reused thus all
153  // variables with ids greater or equal to these values are new). A nullopt
154  // value means that there are not new variables/constraints.
155  void UpdateLinearConstraintMatrix(
156  const SparseDoubleMatrixProto& matrix_updates,
157  std::optional<int64_t> first_new_var_id,
158  std::optional<int64_t> first_new_cstr_id);
159 
160  // Adds the primal solution (if it exists) to the result using the provided
161  // functions to get the status of the solution (GLP_FEAS, ...), its
162  // objective value and the structural variables values.
163  //
164  // Here `col_val` is a functions that takes a column index (i.e. the index of
165  // a structural variable) and returns its primal value in the solution.
166  void AddPrimalSolution(int (*get_prim_stat)(glp_prob*),
167  double (*obj_val)(glp_prob*),
168  double (*col_val)(glp_prob*, int),
169  const ModelSolveParametersProto& model_parameters,
170  SolutionProto& solution_proto);
171 
172  // Adds the dual solution (if it exists) to the result. This function must
173  // only be called after having solved an LP, with the provided methods
174  // depending on the type of LP solved.
175  //
176  // Here `col_dual` is a function that takes a column index (i.e. the index of
177  // a structural variable) and returns its dual value in the solution. The
178  // `row_dual` does the same for a row index (i.e. the index of an auxiliary
179  // variable associated to a constraint).
180  void AddDualSolution(int (*get_dual_stat)(glp_prob*),
181  double (*obj_val)(glp_prob*),
182  double (*row_dual)(glp_prob*, int),
183  double (*col_dual)(glp_prob*, int),
184  const ModelSolveParametersProto& model_parameters,
185  SolutionProto& solution_proto);
186 
187  // Adds a primal or dual ray to the result depending on the value returned by
188  // glp_get_unbnd_ray().
189  absl::Status AddPrimalOrDualRay(
190  const ModelSolveParametersProto& model_parameters,
191  SolveResultProto& result);
192 
193  // Returns an error if the current thread is no thread_id_.
194  absl::Status CheckCurrentThread();
195 
196  // Id of the thread where GlpkSolver was called.
197  const std::thread::id thread_id_;
198 
199  glp_prob* const problem_;
200 
201  Variables variables_;
202  LinearConstraints linear_constraints_;
203 };
204 
206 // Inline functions implementation.
208 
209 bool GlpkSolver::Variables::IsInteger(glp_prob* const problem, const int j) {
210  const int kind = glp_get_col_kind(problem, j);
211  switch (kind) {
212  case GLP_IV:
213  case GLP_BV:
214  // GLP_BV is returned when the GLPK internal kind is GLP_IV and the
215  // bounds are [0,1].
216  return true;
217  case GLP_CV:
218  return false;
219  default:
220  LOG(FATAL) << "Unexpected column kind: " << kind;
221  }
222 }
223 
224 } // namespace math_opt
225 } // namespace operations_research
226 
227 #endif // OR_TOOLS_MATH_OPT_SOLVERS_GLPK_SOLVER_H_
absl::StatusOr< bool > Update(const ModelUpdateProto &model_update) override
static absl::StatusOr< std::unique_ptr< SolverInterface > > New(const ModelProto &model, const InitArgs &init_args)
Definition: glpk_solver.cc:844
absl::StatusOr< SolveResultProto > Solve(const SolveParametersProto &parameters, const ModelSolveParametersProto &model_parameters, MessageCallback message_cb, const CallbackRegistrationProto &callback_registration, Callback cb, SolveInterrupter *interrupter) override
std::function< void(const std::vector< std::string > &)> MessageCallback
std::function< absl::StatusOr< CallbackResultProto >(const CallbackDataProto &)> Callback
SatParameters parameters
GRBmodel * model
Collection of objects used to extend the Constraint Solver library.