Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
linear_solver_callback.h
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
14#ifndef OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_CALLBACK_H_
15#define OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_CALLBACK_H_
16
17#include <cstdint>
18#include <string>
19#include <vector>
20
21#include "absl/container/flat_hash_map.h"
22
23namespace operations_research {
24
25class LinearExpr;
26class LinearRange;
27class MPVariable;
28
29// The current state of the solver when the callback is invoked.
30//
31// For Gurobi, similar to the int 'where' in the Gurobi callback API.
32// See http://www.gurobi.com/documentation/8.0/refman/callback_codes.html
33// for details.
34enum class MPCallbackEvent {
36 // For regaining control of the main thread in single threaded applications,
37 // not for interacting with the solver.
39 // The solver is currently running presolve.
41 // The solver is currently running the simplex method.
43 // The solver is in the MIP loop (called periodically before starting a new
44 // node). Useful to early termination.
45 kMip,
46 // Called every time a new MIP incumbent is found.
48 // Called once per pass of the cut loop inside each MIP node.
50 // Called in each iterate of IPM/barrier method.
52 // The solver is about to log out a message, use this callback to capture it.
54 // The solver is in multi-objective optimization.
56};
57
58std::string ToString(MPCallbackEvent event);
59
60// When querying solution values or modifying the model during a callback, use
61// this API, rather than manipulating MPSolver directly. You should only
62// interact with this object from within MPCallback::RunCallback().
64 public:
65 virtual ~MPCallbackContext() {}
66
67 // What the solver is currently doing. How you can interact with the solver
68 // from the callback depends on this value.
69 virtual MPCallbackEvent Event() = 0;
70
71 // Always false if event is not kMipSolution or kMipNode, otherwise behavior
72 // may be solver dependent.
73 //
74 // For Gurobi, under kMipNode, may be false if the node was not solved to
75 // optimality, see MIPNODE_REL here for details:
76 // http://www.gurobi.com/documentation/8.0/refman/callback_codes.html
77 virtual bool CanQueryVariableValues() = 0;
78
79 // Returns the value of variable from the solver's current state.
80 //
81 // Call only when CanQueryVariableValues() is true.
82 //
83 // At kMipSolution, the solution is integer feasible, while at kMipNode, the
84 // solution solves the current node's LP relaxation (so integer variables may
85 // be fractional).
86 virtual double VariableValue(const MPVariable* variable) = 0;
87
88 // Adds a constraint to the model that strengths the LP relaxation.
89 //
90 // Call only when the event is kMipNode.
91 //
92 // Requires that MPCallback::might_add_cuts() is true.
93 //
94 // This constraint must not cut off integer solutions, it should only
95 // strengthen the LP (behavior is undefined otherwise). Use
96 // MPCallbackContext::AddLazyConstraint() if you are cutting off integer
97 // solutions.
98 virtual void AddCut(const LinearRange& cutting_plane) = 0;
99
100 // Adds a constraint to the model that cuts off an undesired integer solution.
101 //
102 // Call only when the event is kMipSolution or kMipNode.
103 //
104 // Requires that MPCallback::might_add_lazy_constraints() is true.
105 //
106 // Use this to avoid adding a large number of constraints to the model where
107 // most are expected to not be needed.
108 //
109 // Given an integral solution, AddLazyConstraint() MUST be able to detect if
110 // there is a violated constraint, and it is guaranteed that every integer
111 // solution will be checked by AddLazyConstraint().
112 //
113 // Warning(rander): in some solvers, e.g. Gurobi, an integer solution may not
114 // respect a previously added lazy constraint, so you may need to add a
115 // constraint more than once (e.g. due to threading issues).
116 virtual void AddLazyConstraint(const LinearRange& lazy_constraint) = 0;
117
118 // Suggests a (potentially partial) variable assignment to the solver, to be
119 // used as a feasible solution (or part of one). If the assignment is partial,
120 // certain solvers (e.g. Gurobi) will try to compute a feasible solution from
121 // the partial assignment. Returns the objective value of the solution if the
122 // solver supports it.
123 //
124 // Call only when the event is kMipNode.
125 virtual double SuggestSolution(
126 const absl::flat_hash_map<const MPVariable*, double>& solution) = 0;
127
128 // Returns the number of nodes explored so far in the branch and bound tree,
129 // which 0 at the root node and > 0 otherwise.
130 //
131 // Call only when the event is kMipSolution or kMipNode.
132 virtual int64_t NumExploredNodes() = 0;
133};
134
135// Extend this class with model specific logic, and register through
136// MPSolver::SetCallback, passing a pointer to this object.
137//
139 public:
140 // If you intend to call call MPCallbackContext::AddCut(), you must set
141 // might_add_cuts below to be true. Likewise for
142 // MPCallbackContext::AddLazyConstraint() and might_add_lazy_constraints.
144 : might_add_cuts_(might_add_cuts),
145 might_add_lazy_constraints_(might_add_lazy_constraints) {}
146 virtual ~MPCallback() {}
147
148 // Threading behavior may be solver dependent:
149 // * Gurobi: RunCallback always runs on the same thread that you called
150 // MPSolver::Solve() on, even when Gurobi uses multiple threads.
151 virtual void RunCallback(MPCallbackContext* callback_context) = 0;
152
153 bool might_add_cuts() const { return might_add_cuts_; }
155 return might_add_lazy_constraints_;
156 }
157
158 private:
159 bool might_add_cuts_;
160 bool might_add_lazy_constraints_;
161};
162
163// Single callback that runs the list of callbacks given at construction, in
164// sequence.
166 public:
167 explicit MPCallbackList(const std::vector<MPCallback*>& callbacks);
168
169 // Runs all callbacks from the list given at construction, in sequence.
170 void RunCallback(MPCallbackContext* context) override;
171
172 private:
173 const std::vector<MPCallback*> callbacks_;
174};
175
176} // namespace operations_research
177
178#endif // OR_TOOLS_LINEAR_SOLVER_LINEAR_SOLVER_CALLBACK_H_
virtual void AddLazyConstraint(const LinearRange &lazy_constraint)=0
virtual double SuggestSolution(const absl::flat_hash_map< const MPVariable *, double > &solution)=0
virtual MPCallbackEvent Event()=0
virtual double VariableValue(const MPVariable *variable)=0
virtual void AddCut(const LinearRange &cutting_plane)=0
void RunCallback(MPCallbackContext *context) override
Runs all callbacks from the list given at construction, in sequence.
MPCallbackList(const std::vector< MPCallback * > &callbacks)
MPCallback(bool might_add_cuts, bool might_add_lazy_constraints)
virtual void RunCallback(MPCallbackContext *callback_context)=0
The class for variables of a Mathematical Programming (MP) model.
GurobiMPCallbackContext * context
double solution
In SWIG mode, we don't want anything besides these top-level includes.
@ kMultiObj
The solver is in multi-objective optimization.
@ kMipSolution
Called every time a new MIP incumbent is found.
@ kMessage
The solver is about to log out a message, use this callback to capture it.
@ kPresolve
The solver is currently running presolve.
@ kSimplex
The solver is currently running the simplex method.
@ kMipNode
Called once per pass of the cut loop inside each MIP node.
@ kBarrier
Called in each iterate of IPM/barrier method.
absl::string_view ToString(MPSolver::OptimizationProblemType optimization_problem_type)