CGRA-ME
ConstraintSet.cpp
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 #include <CGRA/ConstraintSet.h>
12 
13 ConstraintCache addConstraintsImpl(
14  ConstraintCache&& cache,
15  const ConstraintGenerators& constraint_generators, int verbosity,
16  ConstraintDest destination, const ConstraintAddConf& add_conf, GRBCallbackPublic* cb, GRBModel* model
17 ) {
18  const bool in_callback_mode = destination == ConstraintDest::ViaCallback;
19 
20  MaybeGRBCallback maybe_callback(in_callback_mode ? cb : nullptr);
21 
22  if (in_callback_mode) {
23  maybe_callback.get(); // will throw if we don't have the callback
24  } else {
25  if (not model) {
26  throw std::logic_error("need a model for non-lazy mode");
27  }
28  }
29 
30  struct Counts {
31  int re_adds = 0;
32  int novel = 0;
33  int re_add_avoids = 0;
34 
35  bool isInteresting() const { return re_adds + novel + re_add_avoids != 0; }
36  int totalAdded() const { return re_adds + novel; }
37  };
38 
39  std::map<TypeErasedConstraintEnum, Counts> constraint_numbers;
40 
41  for (auto& group_and_gen : constraint_generators) {
42  const auto& group = group_and_gen.first;
43 
44  // skip if not in configuration
45  if (add_conf.add_modes.find(group) == end(add_conf.add_modes)) {
46  continue;
47  }
48 
49  const auto& add_mode = add_conf.add_modes.at(group);
50  const bool is_callback_mode_group = add_mode == ConstraintAddMode::LazyViaCallback;
51  const bool add_via_lazy_callback = in_callback_mode && is_callback_mode_group;
52  const bool add_to_model_non_lazy = not in_callback_mode && ( add_mode == ConstraintAddMode::NotLazyToModel );
53  const bool add_to_model_lazy = not in_callback_mode && ( add_mode == ConstraintAddMode::LazyToModel1 || add_mode == ConstraintAddMode::LazyToModel2 || add_mode == ConstraintAddMode::LazyToModel3 );
54  const bool adding_lazy = add_via_lazy_callback || add_to_model_lazy;
55 
56  // skip if not adding
57  if (
58  not add_via_lazy_callback
59  && not add_to_model_non_lazy
60  && not add_to_model_lazy
61  ) {
62  continue;
63  }
64 
65  auto& added_constraints = cache.added_constraints[group];
66  auto& constr_nums = constraint_numbers[group];
67  for (auto& id_and_constraint : added_constraints) {
68  if (add_via_lazy_callback) {
69  cb->addLazy(id_and_constraint.second);
70  ++constr_nums.re_adds;
71  }
72  }
73 
74  auto gen_result = group_and_gen.second.gen_func(ConstraintGeneratorParams{ maybe_callback });
75  for (auto& id_and_constraint : gen_result.constraints) {
76  auto& c = id_and_constraint.second;
77  if (add_via_lazy_callback) {
78  if (std::find_if(begin(added_constraints), end(added_constraints), [&](auto&& test) { return *test.first == *id_and_constraint.first; }) == end(added_constraints)) {
79  cb->addLazy(c);
80  added_constraints.emplace_back(std::move(id_and_constraint));
81  ++constr_nums.novel;
82  } else {
83  ++constr_nums.re_add_avoids;
84  }
85  }
86  if (add_to_model_non_lazy || add_to_model_lazy) {
87  std::stringstream name_ss;
88  name_ss << group << '_' << constr_nums.novel;
89  const auto& the_constraint = model->addConstr(c, name_ss.str());
90 
91  // maybe set the constraint as lazy, accornding to the enum
92  if (add_to_model_lazy) {
93  const auto the_value = gurobiLazyIntValueOf(add_mode);
94  model->set(GRB_IntAttr_Lazy, &the_constraint, &the_value, 1); // the 1 is the "length" of the "arrays"
95  }
96 
97  ++constr_nums.novel;
98  }
99  }
100 
101  const char* destination_string = in_callback_mode ? "via callback" : "to model";
102  const char* lazy_string = adding_lazy ? " lazy" : "";
103  const auto lazy_int_string = add_to_model_lazy ? (" L=" + std::to_string(gurobiLazyIntValueOf(add_mode))) : std::string();
104 
105  if (constr_nums.isInteresting() && verbosity > 0) {
106  std::cout
107  << "added this many" << lazy_string << lazy_int_string << " constraints " << destination_string << " for " << group
108  << ": (re-add, novel, re-add-avoid) : " << constr_nums.re_adds << ", " << constr_nums.novel << ", " << constr_nums.re_add_avoids << '\n';
109  }
110  }
111 
112  if (verbosity > 0) {
113  std::cout << "tried adding constraints from " << constraint_numbers.size() << " groups, with no constraints from";
114  std::vector<TypeErasedConstraintEnum> groups_with_no_constraints_added;
115  for (const auto& group_and_nums : constraint_numbers) {
116  if (group_and_nums.second.totalAdded() != 0) { continue; }
117  groups_with_no_constraints_added.push_back(group_and_nums.first);
118  }
119  print_container(std::cout, groups_with_no_constraints_added);
120  std::cout << std::endl;
121  }
122 
123  return std::move(cache);
124 }
125 
126 std::string makeNameSolverSafe(std::string s) {
127  if ((std::ptrdiff_t)s.size() <= GUROBI_MAX_STRING_LENGTH) { return s; }
128 
129  // if too long, take the first MAX-HASH_CHARS chars and append the hash
130  using S = std::remove_cv_t<std::remove_reference_t<decltype(s)>>;
131  const auto hash = std::hash<S>{}(s);
132  using H = std::remove_cv_t<std::remove_reference_t<decltype(hash)>>;
133  using HNL = std::numeric_limits<H>;
134  const int print_radix = 16;
135  const int HASH_CHARS = HNL::digits / print_radix * HNL::radix;
136  s.resize(GUROBI_MAX_STRING_LENGTH);
137  const char hex_digits[] = "0123456789abcdef";
138  for (auto i = 0; i < HASH_CHARS; ++i) {
139  s[GUROBI_MAX_STRING_LENGTH - HASH_CHARS + i] = hex_digits[(hash >> i) & 0x0f];
140  }
141 
142  // LP file format doesn't like colons
143  for (auto& c : s) if (c == ':') c = '-';
144 
145  return s;
146 }
ConstraintSet.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
makeNameSolverSafe
std::string makeNameSolverSafe(std::string s)
Definition: ConstraintSet.cpp:126
GUROBI_MAX_STRING_LENGTH
const int GUROBI_MAX_STRING_LENGTH
Definition: ConstraintSet.h:418
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
print_container
void print_container(OSTREAM &&os, const CONTAINER &c, const T1 &element_separator, const T2 &container_prefix, const T3 &container_suffix, PRINTER &&element_printer=PRINTER{})
Definition: Collections.h:435
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