CGRA-ME
ConstraintSet.h
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 #ifndef __CONSTRAINT_SET_H__
12 #define __CONSTRAINT_SET_H__
13 
14 #include <CGRA/ILPMapper.h>
15 #include <CGRA/TupleHash.h>
16 
17 #include <algorithm>
18 #include <stdexcept>
19 #include <functional>
20 
21 #ifdef USE_GUROBI
22 #include <gurobi_c++.h>
23 
27 class GRBCallbackPublic : public GRBCallback {
28 public:
29  GRBCallbackPublic() = default;
30  GRBCallbackPublic(const GRBCallbackPublic&) = default;
31  GRBCallbackPublic& operator=(const GRBCallbackPublic&) = default;
32  GRBCallbackPublic(GRBCallbackPublic&&) = default;
33  GRBCallbackPublic& operator=(GRBCallbackPublic&&) = default;
34 
35  using GRBCallback::where;
36 
37  using GRBCallback::callback;
38  using GRBCallback::getDoubleInfo;
39  using GRBCallback::getIntInfo;
40  using GRBCallback::getStringInfo;
41  using GRBCallback::getSolution;
42  using GRBCallback::getNodeRel;
43  using GRBCallback::setSolution;
44  //using GRBCallback::useSolution;
45  using GRBCallback::addCut;
46  using GRBCallback::addLazy;
47  using GRBCallback::abort;
48 };
49 
53 template<typename FUNC>
54 class OnMIPSolutionFunctorGRBCallback : public GRBCallbackPublic {
55 public:
56  OnMIPSolutionFunctorGRBCallback(FUNC on_MIP_solution_functor)
57  : on_MIP_solution_functor(std::move(on_MIP_solution_functor))
58  { }
59 
60  void callback() override {
61  if (where == GRB_CB_MIPSOL) {
62  onMIPSolution();
63  }
64  }
65 
66  void onMIPSolution() {
67  on_MIP_solution_functor(*this);
68  }
69 
70 private:
71  FUNC on_MIP_solution_functor;
72 };
73 
74 template<typename FUNC>
75 auto makeOnMIPSolutionFunctorGRBCallback(FUNC&& on_MIP_solution_functor) {
76  return OnMIPSolutionFunctorGRBCallback<FUNC>(std::forward<FUNC>(on_MIP_solution_functor));
77 }
78 
85 class MaybeGRBCallback {
86 public:
87  MaybeGRBCallback(GRBCallbackPublic* impl)
88  : impl(impl)
89  { }
90 
91  bool hasImpl() const { return impl != nullptr; }
92  operator bool() const { return hasImpl(); }
93 
94  GRBCallbackPublic& get() const {
95  if (not hasImpl()) { throw std::logic_error("Cannot get implementation - implementation not provided/implementation pointer is null"); }
96  else { return *impl; }
97  }
98 
99  GRBCallbackPublic& operator*() const { return get(); }
100  GRBCallbackPublic* operator->() const { return &(**this); }
101 
102 private:
103  GRBCallbackPublic* impl;
104 };
105 
106 
113 struct ConstraintID {
114  virtual bool operator==(const ConstraintID&) const = 0;
115  virtual std::size_t hash() const = 0;
116  virtual ~ConstraintID() = default;
117 };
118 
119 namespace std {
120  template<>
121  struct hash<ConstraintID> {
122  std::size_t operator()(const ConstraintID& cid) const {
123  return cid.hash();
124  }
125  };
126 }
127 
134 template<typename REPR>
135 struct StandardConstraintID : ConstraintID {
136 
137  REPR data;
138 
139  template<typename T>
140  StandardConstraintID(T&& t)
141  : data(t)
142  { }
143 
144  StandardConstraintID(const StandardConstraintID&) = default;
145  StandardConstraintID& operator=(const StandardConstraintID&) = default;
146  StandardConstraintID(StandardConstraintID&&) = default;
147  StandardConstraintID& operator=(StandardConstraintID&&) = default;
148 
149  bool operator==(const ConstraintID& rhs) const override {
150  auto* rhs_ptr = dynamic_cast<const StandardConstraintID*>(&rhs);
151  return rhs_ptr && this->data == rhs_ptr->data;
152  }
153 
154  std::size_t hash() const override {
155  return std::hash<REPR>{}(data);
156  }
157 };
158 
165 template<typename... TUP_ARGS>
166 struct TupleConstraintID : ConstraintID {
167 
168  std::tuple<TUP_ARGS...> data;
169 
170  template<typename... T>
171  TupleConstraintID(T&&... t)
172  : data(std::forward<T>(t)...)
173  { }
174 
175  TupleConstraintID(const TupleConstraintID&) = default;
176  TupleConstraintID& operator=(const TupleConstraintID&) = default;
177  TupleConstraintID(TupleConstraintID&&) = default;
178  TupleConstraintID& operator=(TupleConstraintID&&) = default;
179 
180  bool operator==(const ConstraintID& rhs) const override {
181  auto* rhs_ptr = dynamic_cast<const TupleConstraintID*>(&rhs);
182  return rhs_ptr && this->data == rhs_ptr->data;
183  }
184 
185  std::size_t hash() const override {
186  return tuple_hash::hashValue(data);
187  }
188 };
189 
195 template<typename REPR>
196 std::unique_ptr<StandardConstraintID<REPR>> makeNewStandardConstraintID(REPR data) {
197  return std::make_unique<StandardConstraintID<REPR>>(std::forward<REPR>(data));
198 }
199 
200 template<typename... TUP_ARGS>
201 std::unique_ptr<TupleConstraintID<TUP_ARGS...>> makeNewTupleConstraintID(TUP_ARGS&&... targs) {
202  return std::make_unique<TupleConstraintID<TUP_ARGS...>>(std::forward<TUP_ARGS>(targs)...);
203 }
204 
205 using TypeErasedConstraintEnum = int;
206 
207 enum class ConstraintAddMode {
208  LazyViaCallback, //< Only add if adding by callback
209  LazyToModel1, //< Only add if adding to the model, and set Lazy=1 on the constraint
210  LazyToModel2, //< Only add if adding to the model, and set Lazy=2 on the constraint
211  LazyToModel3, //< Only add if adding to the model, and set Lazy=3 on the constraint
212  NotLazyToModel, //< Only add if adding to the model, does not set Lazy to any value
213 };
214 
219 struct ConstraintAddConf {
228  template<typename CONTAINER>
229  ConstraintAddConf(const CONTAINER& amodes_and_cgroups) {
230  for (auto& amode_and_cgroup : amodes_and_cgroups) {
231  addAs(amode_and_cgroup.first, amode_and_cgroup.second);
232  }
233  }
234 
235  template<typename ConstraintEnum, typename CGROUPS = std::set<ConstraintEnum>, typename CONTAINER = std::vector<std::pair<ConstraintAddMode, CGROUPS>>>
236  static ConstraintAddConf make(const CONTAINER& amodes_and_cgroups = {}) {
237  return {amodes_and_cgroups};
238  }
239 
246  template<typename CGROUPS>
247  // template<typename ConstraintEnum, typename CGROUPS = std::set<ConstraintEnum>>
248  void addAs(ConstraintAddMode amode, const CGROUPS& cgroups, bool check_overwrite = true) {
249  for (auto& cg : cgroups) {
250  auto emplace_result = add_modes.emplace((TypeErasedConstraintEnum)cg, amode);
251  if (not emplace_result.second) {
252  if (check_overwrite) {
253  throw std::logic_error("constraint already added");
254  } else {
255  emplace_result.first->second = amode;
256  }
257  }
258  }
259  }
260 
261  bool willRequireLazyModelAttribute() {
262  return std::find_if(begin(add_modes), end(add_modes), [](auto&& e) {
263  return e.second == ConstraintAddMode::LazyViaCallback;
264  }) != end(add_modes);
265  }
266 
267  template<typename, typename>
268  friend class ConstraintSet;
269  std::map<TypeErasedConstraintEnum, ConstraintAddMode> add_modes = {};
270 };
271 
272 using IDAndConstraint = std::pair<std::unique_ptr<ConstraintID>, GRBTempConstr>;
273 
277 struct ConstraintCache {
278  std::map<TypeErasedConstraintEnum, std::vector<IDAndConstraint>> added_constraints;
279 };
280 
281 struct GenFuncReturn {
282  std::vector<IDAndConstraint> constraints = {};
283 };
284 
285 struct ConstraintGeneratorParams {
286  MaybeGRBCallback callback;
287 
288  bool inIncrementalMode() { return callback; }
289  auto makeReturnValue() { return GenFuncReturn(); }
290 };
291 
292 using CGenFunc = std::function<GenFuncReturn(ConstraintGeneratorParams)>;
293 
294 struct CGen {
295  CGenFunc gen_func;
296 };
297 
298 using ConstraintGenerators = std::vector<std::pair<TypeErasedConstraintEnum, CGen>>;
299 
300 enum class ConstraintDest { ToModel, ViaCallback, };
301 
302 [[nodiscard]]
303 ConstraintCache addConstraintsImpl(
304  ConstraintCache&& cache,
305  const ConstraintGenerators& constraint_generators, int verbosity,
306  ConstraintDest destination, const ConstraintAddConf& add_conf, GRBCallbackPublic* cb, GRBModel* model
307 );
308 
313 template<typename ConstraintEnum, typename SetOfConstraintEnums = std::set<ConstraintEnum>>
314 class ConstraintSet {
315 public:
321  void registerGenerator(ConstraintEnum cgroup, CGenFunc constraint_generator) {
322  constraint_generators.emplace_back((TypeErasedConstraintEnum)cgroup, CGen {
323  std::move(constraint_generator),
324  });
325  }
326 
327  SetOfConstraintEnums getAllConstraintGroupsRegistered() const {
328  SetOfConstraintEnums res;
329  auto& cgens = constraint_generators;
330  std::transform(begin(cgens), end(cgens), std::inserter(res, end(res)), [](auto&& e) { return (ConstraintEnum)e.first; });
331  return res;
332  }
333 
348  [[nodiscard]]
349  ConstraintCache addConstraintsViaCallback(
350  ConstraintCache&& cache,
351  const ConstraintAddConf& add_conf, GRBCallbackPublic& cb
352  ) const {
353  return addConstraintsImpl(std::move(cache), constraint_generators, verbosity, ConstraintDest::ViaCallback, add_conf, &cb, nullptr);
354  }
355 
360  [[nodiscard]]
361  ConstraintCache addConstraintsToModel(
362  ConstraintCache&& cache,
363  const ConstraintAddConf& add_conf, GRBModel& model
364  ) const {
365  return addConstraintsImpl(std::move(cache), constraint_generators, verbosity, ConstraintDest::ToModel, add_conf, nullptr, &model);
366  }
367 
371  void setVerbosity(int i) { verbosity = i; }
372 
373 private:
374  ConstraintGenerators constraint_generators = {};
375  int verbosity = 0;
376 };
377 
381 inline int gurobiLazyIntValueOf(ConstraintAddMode add_mode) {
382  switch (add_mode) {
383  case ConstraintAddMode::LazyViaCallback: return 0;
384  case ConstraintAddMode::LazyToModel1: return 1;
385  case ConstraintAddMode::LazyToModel2: return 2;
386  case ConstraintAddMode::LazyToModel3: return 3;
387  case ConstraintAddMode::NotLazyToModel: return 0;
388  default: throw std::out_of_range("unexpected ConstraintAddMode");
389  }
390 }
391 
404 template<typename WRAPPER_EXCEPTION = cgrame_error>
405 [[noreturn]] void throwExceptionButWrapIfGurobiException(std::exception_ptr eptr) {
406  try {
407  std::rethrow_exception(eptr);
408  } catch (const GRBException& grbex) {
409  std::throw_with_nested(WRAPPER_EXCEPTION(
410  "wrapped GRBException with code=" + std::to_string(grbex.getErrorCode())
411  + " and message='" + grbex.getMessage() + '\''
412  ));
413  }
414 }
415 
416 #endif /* USE_GUROBI */
417 
418 const int GUROBI_MAX_STRING_LENGTH = 255;
419 
426 std::string makeNameSolverSafe(std::string s);
427 
428 #endif /* __CONSTRAINT_SET_H__ */
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
tuple_hash::hashValue
std::size_t hashValue(const T &t)
Definition: TupleHash.h:72
GUROBI_MAX_STRING_LENGTH
const int GUROBI_MAX_STRING_LENGTH
Definition: ConstraintSet.h:418
operator==
bool operator==(const OpGraph &lhs, const OpGraph &rhs)
Definition: OpGraph.cpp:1159
makeNameSolverSafe
std::string makeNameSolverSafe(std::string s)
Definition: ConstraintSet.cpp:126
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
TupleHash.h
addConstraintsImpl
ConstraintCache addConstraintsImpl(ConstraintCache &&cache, const ConstraintGenerators &constraint_generators, int verbosity, ConstraintDest destination, const ConstraintAddConf &add_conf, GRBCallbackPublic *cb, GRBModel *model)
Definition: ConstraintSet.cpp:13
ILPMapper.h