forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgurobi_solver.h
205 lines (182 loc) · 8.66 KB
/
gurobi_solver.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#pragma once
#include <functional>
#include <memory>
#include <string>
#include "drake/common/autodiff.h"
#include "drake/common/drake_copyable.h"
#include "drake/solvers/decision_variable.h"
#include "drake/solvers/solver_base.h"
namespace drake {
namespace solvers {
/// The Gurobi solver details after calling Solve() function. The user can call
/// MathematicalProgramResult::get_solver_details<GurobiSolver>() to obtain the
/// details.
struct GurobiSolverDetails {
/// The gurobi optimization time. Please refer to
/// https://www.gurobi.com/documentation/9.5/refman/runtime.html
double optimizer_time{};
/// The error message returned from Gurobi call. Please refer to
/// https://www.gurobi.com/documentation/9.5/refman/error_codes.html
int error_code{};
/// The status code when the optimize call has returned. Please refer to
/// https://www.gurobi.com/documentation/9.5/refman/optimization_status_codes.html
int optimization_status{};
/// The best known bound on the optimal objective. This is used in mixed
/// integer optimization. Please refer to
/// https://www.gurobi.com/documentation/9.5/refman/objbound.html
double objective_bound{NAN};
};
/// An implementation of SolverInterface for the commercially-licensed Gurobi
/// solver (https://www.gurobi.com/).
///
/// The default build of Drake is not configured to use Gurobi, so therefore
/// SolverInterface::available() will return false. You must compile Drake
/// from source in order to link against Gurobi. For details, refer to the
/// documentation at https://drake.mit.edu/bazel.html#proprietary-solvers.
///
/// The GRB_LICENSE_FILE environment variable controls whether or not
/// SolverInterface::enabled() returns true. If it is set to any non-empty
/// value, then the solver is enabled; otherwise, the solver is not enabled.
///
/// Gurobi solver supports options/parameters listed in
/// https://www.gurobi.com/documentation/9.1/refman/parameters.html. On top of
/// these options, we provide the following additional options
/// 1. "GRBwrite", set to a file name so that Gurobi solver will write the
/// optimization model to this file, check
/// https://www.gurobi.com/documentation/9.1/refman/py_model_write.html for
/// more details, such as all supported file extensions. Set this option to
/// "" if you don't want to write to file. Default is not to write to a file.
/// 2. "GRBcomputeIIS", set to 1 to compute an Irreducible Inconsistent
/// Subsystem (IIS) when the problem is infeasible. Refer to
/// https://www.gurobi.com/documentation/9.1/refman/py_model_computeiis.html
/// for more details. Often this method is called together with
/// setting GRBwrite to "FILENAME.ilp" to write IIS to a file with extension
/// "ilp". Default is not to compute IIS.
class GurobiSolver final : public SolverBase {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(GurobiSolver)
/// Type of details stored in MathematicalProgramResult.
using Details = GurobiSolverDetails;
GurobiSolver();
~GurobiSolver() final;
/// Contains info returned to a user function that handles
/// a Node or Solution callback.
/// @see MipNodeCallbackFunction
/// @see MipSolCallbackFunction
struct SolveStatusInfo {
/// Runtime as of this callback.
double reported_runtime{};
/// Objective of current solution.
double current_objective{};
/// Objective of best solution yet.
double best_objective{};
/// Best known objective lower bound.
double best_bound{};
/// Number of nodes explored so far.
int explored_node_count{};
/// Number of feasible sols found so far.
int feasible_solutions_count{};
};
/// Users can supply a callback to be called when the Gurobi solver
/// finds an intermediate solution node, which may not be feasible.
/// See Gurobi reference manual for more detail on callbacks:
/// https://www.gurobi.com/documentation/9.5/refman/callback_codes.html.
/// The user may supply a partial solution in the VectorXd and
/// VectorXDecisionVariable arguments that will be passed to Gurobi
/// as a candidate feasible solution.
/// See gurobi_solver_test.cc for an example of using std::bind
/// to create a callback of this signature, while allowing
/// additional data to be passed through.
/// @param MathematicalProgram& The optimization wrapper, whose
/// current variable values (accessible via
/// MathematicalProgram::GetSolution) will be set to the intermediate
/// solution values.
/// @param SolveStatusInfo& Intermediate solution status information values
/// queried from Gurobi.
/// @param VectorXd* User may assign this to be the values of the variable
/// assignments.
/// @param VectorXDecisionVariable* User may assign this to be the decision
/// variables being assigned. Must have the same number of elements as
/// the VectorXd assignment.
typedef std::function<void(const MathematicalProgram&,
const SolveStatusInfo& callback_info,
Eigen::VectorXd*, VectorXDecisionVariable*)>
MipNodeCallbackFunction;
/// Registers a callback to be called at intermediate solutions
/// during the solve.
/// @param callback User callback function.
/// @param user_data Arbitrary data that will be passed to the user
/// callback function.
void AddMipNodeCallback(const MipNodeCallbackFunction& callback) {
mip_node_callback_ = callback;
}
/// Users can supply a callback to be called when the Gurobi solver
/// finds a feasible solution.
/// See Gurobi reference manual for more detail on callbacks:
/// https://www.gurobi.com/documentation/9.5/refman/callback_codes.html.
/// See gurobi_solver_test.cc for an example of using std::bind
/// to create a callback of this signature, while allowing
/// additional data to be passed through.
/// @param MathematicalProgram& The optimization wrapper, whose
/// current variable values (accessible via
/// MathematicalProgram::GetSolution) will be set to the intermediate
/// solution values.
/// @param SolveStatusInfo& Intermediate solution status information values
/// queried from Gurobi.
/// @param void* Arbitrary data supplied during callback registration.
typedef std::function<void(const MathematicalProgram&,
const SolveStatusInfo& callback_info)>
MipSolCallbackFunction;
/// Registers a callback to be called at feasible solutions
/// during the solve.
/// @param callback User callback function.
/// @param usrdata Arbitrary data that will be passed to the user
/// callback function.
void AddMipSolCallback(const MipSolCallbackFunction& callback) {
mip_sol_callback_ = callback;
}
/**
* This type contains a valid Gurobi license environment, and is only to be
* used from AcquireLicense().
*/
class License;
/**
* This acquires a Gurobi license environment shared among all GurobiSolver
* instances; the environment will stay valid as long as at least one
* shared_ptr returned by this function is alive.
* Call this ONLY if you must use different MathematicalProgram
* instances at different instances in time, and repeatedly acquiring the
* license is costly (e.g., requires contacting a license server).
* @return A shared pointer to a license environment that will stay valid
* as long as any shared_ptr returned by this function is alive. If Gurobi
* not available in your build, this will return a null (empty) shared_ptr.
* @throws std::exception if Gurobi is available but a license cannot be
* obtained.
*/
static std::shared_ptr<License> AcquireLicense();
/// @name Static versions of the instance methods with similar names.
//@{
static SolverId id();
static bool is_available();
/// Returns true iff the environment variable GRB_LICENSE_FILE has been set
/// to a non-empty value.
static bool is_enabled();
static bool ProgramAttributesSatisfied(const MathematicalProgram&);
static std::string UnsatisfiedProgramAttributes(const MathematicalProgram&);
//@}
// A using-declaration adds these methods into our class's Doxygen.
using SolverBase::Solve;
private:
void DoSolve(const MathematicalProgram&, const Eigen::VectorXd&,
const SolverOptions&, MathematicalProgramResult*) const final;
// Note that this is mutable to allow latching the allocation of env_
// during the first call of Solve() (which avoids grabbing a Gurobi license
// before we know that we actually want one).
mutable std::shared_ptr<License> license_;
// Callbacks and generic user data to pass through,
// or NULL if no callback has been supplied.
MipNodeCallbackFunction mip_node_callback_;
MipSolCallbackFunction mip_sol_callback_;
};
} // end namespace solvers
} // end namespace drake