3 #ifndef ILP_MODEL_MULTI_HPP
4 #define ILP_MODEL_MULTI_HPP
6 #include "boost/multi_array.hpp"
11 #include "ilp_common.hpp"
12 #include "utils/profiling.hpp"
16 enum vertex_subgraph_nr_t { vertex_subgraph_nr = 201 };
17 BOOST_INSTALL_PROPERTY(vertex, subgraph_nr);
19 enum vertex_layer_t { vertex_layer = 202 };
20 BOOST_INSTALL_PROPERTY(vertex, layer);
27 typedef boost::adjacency_list<
30 boost::bidirectionalS,
31 boost::property<boost::vertex_subgraph_nr_t, size_t,
32 boost::property<boost::vertex_layer_t, size_t>
39 using EdgeVarMapMatrix = boost::multi_array<EdgeVarMap<Graph>, 2>;
43 using TranslateMatrix = boost::multi_array<TranslateBiMap<Graph, AuxGraphs>, 2>;
47 struct var_collection {
48 const Instance<Graph>& I;
49 const size_t max_multi;
51 EdgeVarMap<Graph> x,z;
52 EdgeVarMapMatrix<Graph> y;
53 std::vector<vertex_var_map<Graph> > s, tp, tc;
55 var_collection(
const Instance<Graph>& _I):
57 max_multi(_I.get_max_multiplicity_no_update()),
58 y(
boost::extents[max_multi][max_multi]),
68 class LazyCyclesBlockCallback:
public IloCplex::LazyConstraintCallbackI{
69 const var_collection<Graph>& vars;
70 callback_statistics& stats;
74 void build_aux_graph(AuxGraphs& aux, TranslateMatrix<Graph>& translate);
75 void cleanup_aux_graph(AuxGraphs& aux, TranslateMatrix<Graph>& translate);
78 IloCplex::CallbackI* duplicateCallback()
const{
79 return (
new (getEnv()) LazyCyclesBlockCallback(getEnv(), vars, stats));
82 LazyCyclesBlockCallback(IloEnv env,
const var_collection<Graph>& _vars, callback_statistics& _stats):
83 IloCplex::LazyConstraintCallbackI(env),
92 IloCplex::Callback GetLazyCyclesBlock(IloEnv env,
const var_collection<Graph>& vars, callback_statistics& stats) {
93 return (
new (env) LazyCyclesBlockCallback<Graph>(env, vars, stats));
98 void LazyCyclesBlockCallback<Graph>::build_aux_graph(AuxGraphs& aux, TranslateMatrix<Graph>& translate){
99 const Instance<Graph>& I = vars.I;
102 for(
size_t i = 0; i < vars.max_multi; ++i){
103 for(
size_t j = 0; j < vars.max_multi; ++j){
104 for(
const auto& y : vars.y[i][j]){
105 const VertexPair<Graph>& uv = y.first;
106 const Vertex<Graph>& u = uv.first;
107 const Vertex<Graph>& v = uv.second;
108 const IloNumVar& y_val = y.second;
109 const unsigned layer = I.is_matching_edge(uv) ? 0 : 1;
111 if(is_true(getValue(y_val))){
114 auto u_it = translate[i][layer].left.find(u);
115 if(u_it == translate[i][layer].left.end()){
116 const Vertex<AuxGraphs> au = boost::add_vertex(aux);
117 boost::put(vertex_subgraph_nr, aux, au, i);
118 boost::put(vertex_layer, aux, au, layer);
119 u_it = translate[i][layer].left.insert(u_it,
typename TranslateBiMap<Graph, AuxGraphs>::left_map::value_type(u, au));
122 auto v_it = translate[j][1-layer].left.find(v);
123 if(v_it == translate[j][1-layer].left.end()){
124 const Vertex<AuxGraphs> av = boost::add_vertex(aux);
125 boost::put(vertex_subgraph_nr, aux, av, j);
126 boost::put(vertex_layer, aux, av, 1-layer);
127 v_it = translate[j][1-layer].left.insert(v_it,
typename TranslateBiMap<Graph, AuxGraphs>::left_map::value_type(v, av));
131 const Vertex<AuxGraphs>& aux_u = u_it->second;
132 const Vertex<AuxGraphs>& aux_v = v_it->second;
133 boost::add_edge(aux_u, aux_v, aux);
142 template<
class Graph>
143 void LazyCyclesBlockCallback<Graph>::cleanup_aux_graph(AuxGraphs& aux, TranslateMatrix<Graph>& translate){
145 VertexSet<AuxGraphs>* pending =
new VertexSet<Graph>();
146 DEBUG5(std::cout <<
"reachable from s: ");
147 for(
size_t i = 0; i < vars.max_multi; ++i)
148 for(
const auto& y_su : vars.s[i])
149 if(is_true(getValue(y_su.second))) {
150 const Vertex<Graph>& u = y_su.first;
151 DEBUG5(std::cout << VertexAndGraph<Graph>(u, *vars.I.g) <<
" ");
153 auto u_iter = translate[i][0].left.find(u);
154 if(u_iter != translate[i][0].left.end()) pending->insert(u_iter->second);
156 DEBUG5(std::cout <<
"."<< std::endl);
159 unsigned current_layer = 0;
160 while(!pending->empty()){
161 VertexSet<AuxGraphs>* neighbors =
new VertexSet<AuxGraphs>();
162 for(
const Vertex<AuxGraphs>& aux_u : *pending){
163 const size_t subgraph_nr = boost::get(vertex_subgraph_nr, aux, aux_u);
164 const size_t layer = boost::get(vertex_layer, aux, aux_u);
166 for(OEdgeIterRange<AuxGraphs> r = boost::out_edges(aux_u, aux); r.first != r.second; ++r.first)
167 neighbors->insert(boost::target(*r.first, aux));
169 translate[subgraph_nr][layer].right.erase(aux_u);
171 boost::clear_vertex(aux_u, aux);
172 boost::remove_vertex(aux_u, aux);
174 current_layer = 1 - current_layer;
181 template<
class Graph>
182 void LazyCyclesBlockCallback<Graph>::main(){
183 stats.time_spent.resume();
184 DEBUG5(std::cout <<
"callback starts"<<std::endl);
186 const Graph& g = *vars.I.g;
189 TranslateMatrix<Graph> translate(boost::extents[vars.max_multi][2]);
192 DEBUG5(std::cout <<
"building auxiliary graph..."<<std::endl);
193 build_aux_graph(aux, translate);
194 DEBUG5(std::cout <<
"built aux graph with "<<boost::num_vertices(aux)<<
" vertices & "<<boost::num_edges(aux)<<
" edges"<<std::endl);
196 DEBUG5(std::cout <<
"removing valid paths/cycles from auxiliary graph..."<<std::endl);
197 cleanup_aux_graph(aux, translate);
198 DEBUG5(std::cout <<
"after cleanup, "<<boost::num_vertices(aux)<<
" vertices & "<<boost::num_edges(aux)<<
" edges remain"<<std::endl);
203 unsigned num_new_cuts = 0;
204 #ifdef LAZY_ADD_ALL_CYCLES
205 while(boost::num_edges(aux)){
207 if(boost::num_edges(aux)){
209 IloExpr expr(getEnv()), rev_expr(getEnv());
210 VertexSet<AuxGraphs> S;
212 DEBUG5(std::cout <<
"forbidding cyclic structure: ");
214 size_t max_multiplicity = 1;
215 const Edge<AuxGraphs> e = *(boost::edges(aux).first);
216 const Vertex<AuxGraphs> x = boost::source(e, aux);
217 VertexQueue<AuxGraphs> pending;
220 while(!pending.empty()){
221 const Vertex<AuxGraphs> aux_u = pending.front(); pending.pop();
222 const unsigned u_subgraph_nr = boost::get(vertex_subgraph_nr, aux, aux_u);
223 const unsigned u_layer = boost::get(vertex_layer, aux, aux_u);
224 const Vertex<Graph>& u = translate[u_subgraph_nr][u_layer].right.at(aux_u);
225 for(OEdgeIterRange<AuxGraphs> r = boost::out_edges(aux_u, aux); r.first != r.second;){
226 const Edge<AuxGraphs> aux_uv = *r.first;
227 const Vertex<AuxGraphs> aux_v = boost::target(aux_uv, aux);
228 const unsigned v_subgraph_nr = boost::get(vertex_subgraph_nr, aux, aux_v);
229 const unsigned v_layer = boost::get(vertex_layer, aux, aux_v);
231 const Vertex<Graph>& v = translate[v_subgraph_nr][v_layer].right.at(aux_v);
232 const VertexPair<Graph> uv = VertexPair<Graph>(u,v);
233 const VertexPair<Graph> vu = VertexPair<Graph>(v,u);
235 const Edge<Graph> e = boost::edge(u, v, g).first;
236 max_multiplicity = std::max(max_multiplicity, boost::get(edge_multiplicity, g, e));
238 DEBUG5(std::cout <<
" " << VertexPairAndGraph<Graph>(uv, g));
241 expr -= vars.y[u_layer][v_layer].at(uv);
242 rev_expr -= vars.y[v_layer][u_layer].at(vu);
246 boost::remove_edge(aux_uv, aux);
249 if(!contains(S, aux_v)) {
255 DEBUG5(std::cout << std::endl);
256 const size_t S_size = S.size();
258 for(
const Vertex<AuxGraphs>& aux_u : S){
259 const unsigned u_subgraph = boost::get(vertex_subgraph_nr, aux, aux_u);
260 const unsigned u_layer = boost::get(vertex_layer, aux, aux_u);
261 const Vertex<Graph>& u = translate[u_subgraph][u_layer].right.at(aux_u);
264 for(AdjIterRange<Graph> r = boost::adjacent_vertices(u, g); r.first != r.second; ++r.first){
265 const Vertex<Graph>& v = *r.first;
266 for(
size_t v_layer = 0; v_layer < vars.max_multi; ++v_layer){
267 const auto aux_v_it = translate[v_layer][0].left.find(v);
269 if( (aux_v_it == translate[v_layer][0].left.end()) || !contains(S, aux_v_it->second)){
270 const VertexPair<Graph> uv = VertexPair<Graph>(u, v);
271 const VertexPair<Graph> vu = VertexPair<Graph>(v, u);
273 expr += (double)(S_size * max_multiplicity) * vars.y[u_layer][v_layer].at(uv);
274 rev_expr += (double)(S_size * max_multiplicity) * vars.y[v_layer][u_layer].at(vu);
280 expr += (double)(S_size * max_multiplicity) * vars.tc[u_subgraph].at(u);
281 rev_expr += (double)(S_size * max_multiplicity) * vars.tc[u_subgraph].at(u);
289 #ifdef LAZY_ADD_ALL_CYCLES
295 DEBUG2(std::cout <<
"======= callback called, added "<<num_new_cuts<<
" new cuts ======"<<std::endl);
296 stats.times_called++;
297 stats.cuts_added += num_new_cuts;
298 stats.time_spent.pause();
302 #warning TODO: use each edges multiplicity to restrict the domain of its variable instead of adding a constraint
304 template<
class Graph>
305 void populate_variables(IloEnv& env, var_collection<Graph>& vars){
306 const Instance<Graph>& I = vars.I;
307 const Graph& g = *I.g;
308 const size_t max_multi = vars.max_multi;
310 DEBUG5(std::cout <<
"creating z_{u,v}/x_{u,v}/y_uv"<<std::endl);
311 for(EdgeIterRange<Graph> e = boost::edges(g); e.first != e.second; ++e.first){
312 const Vertex<Graph>& u = source(*e.first, g);
313 const Vertex<Graph>& v = target(*e.first, g);
314 const std::string uname = std::to_string(boost::get(boost::vertex_name, g, u));
315 const std::string vname = std::to_string(boost::get(boost::vertex_name, g, v));
318 const std::string zname(
"z_" + uname +
"," + vname);
319 vars.z.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, zname.c_str()));
320 const std::string xname(
"x_" + uname +
"," + vname);
321 vars.x.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, max_multi, IloNumVar::Int, xname.c_str()));
323 const std::string yname1(
"y_" + uname +
"," + vname);
324 const std::string yname2(
"y_" + vname +
"," + uname);
325 for(
size_t i = 0; i < max_multi; ++i)
326 for(
size_t j = 0; j < max_multi; ++j){
327 vars.y[i][j].emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, yname1.c_str()));
328 vars.y[i][j].emplace(std::piecewise_construct, std::make_tuple(v,u), std::make_tuple(env, 0, 1, IloNumVar::Bool, yname2.c_str()));
331 DEBUG5(std::cout <<
"creating s/tp/tc interaction variables"<<std::endl);
333 for(VertexIterRange<Graph> v = boost::vertices(g); v.first != v.second; ++v.first){
334 const Vertex<Graph>& u = *v.first;
335 const std::string name(std::to_string(boost::get(boost::vertex_name, g, u)));
336 for(
size_t i = 0; i < max_multi; ++i){
338 vars.s[i].emplace(std::piecewise_construct, std::make_tuple(u), std::make_tuple(env, 0, 1, IloNumVar::Bool, (
"y_s," + name).c_str()));
340 vars.tp[i].emplace(std::piecewise_construct, std::make_tuple(u), std::make_tuple(env, 0, 1, IloNumVar::Bool, (
"y_" + name +
",tp").c_str()));
342 vars.tc[i].emplace(std::piecewise_construct, std::make_tuple(u), std::make_tuple(env, 0, 1, IloNumVar::Bool, (
"y_" + name +
",tc").c_str()));
348 template<
class Graph>
349 void populate_constraints(IloEnv& env, IloRangeArray& c,
const var_collection<Graph>& vars){
350 const Instance<Graph>& I = vars.I;
351 const Graph& g(*I.g);
354 DEBUG5(std::cout <<
"adding (16): x_e = 0 --> z_e = 0"<<std::endl);
355 for(
auto x : vars.x){
356 const VertexPair<Graph> uv = x.first;
360 expr -= vars.z.at(uv);
365 DEBUG5(std::cout <<
"adding (17): of all the representations of e, exactly x_e should be chosen"<<std::endl);
366 for(
auto x : vars.x){
367 const VertexPair<Graph> uv = x.first;
368 const VertexPair<Graph> vu(uv.second, uv.first);
371 for(
size_t i = 0; i < vars.max_multi; ++i){
372 for(
size_t j = 0; j < vars.max_multi; ++j){
373 expr += vars.y[i][j].at(uv);
374 expr += vars.y[i][j].at(vu);
382 DEBUG5(std::cout <<
"adding (2'): any matching-edge e should be chosen between 1 and m(e) times"<<std::endl);
384 if(I.is_matching_edge(x.first)) {
385 const Edge<Graph> e = boost::edge(x.first.first, x.first.second, g).first;
386 c.add(x.second >= 1);
387 c.add(x.second <= (
double)boost::get(boost::edge_multiplicity, g, e));
388 DEBUG3(std::cout<<
"allowing "<<EdgeAndGraph<Graph>(e, g)<<
" with multi "<<(
double)boost::get(boost::edge_multiplicity, g, e)<<std::endl);
392 DEBUG5(std::cout <<
"adding (4)&(6): there should be at most sigma_p paths & sigma_c cycles"<<std::endl);
394 IloExpr p_expr(env), c_expr(env);
395 for(
size_t i = 0; i < vars.max_multi; ++i) {
396 for(
auto y : vars.tp[i]) p_expr += y.second;
397 for(
auto y : vars.tc[i]) c_expr += y.second;
399 c.add(p_expr <= (
double)I.num_paths);
400 c.add(c_expr <= (
double)I.num_cycles);
404 DEBUG5(std::cout <<
"adding (18): flow conservation"<<std::endl);
405 for(VertexIterRange<Graph> u = boost::vertices(g); u.first != u.second; ++u.first){
406 for(
size_t i = 0; i < vars.max_multi; ++i){
407 for(
size_t layer = 0; layer < 2; ++layer){
409 for(AdjIterRange<Graph> nh = boost::adjacent_vertices(*u.first, g); nh.first != nh.second; ++nh.first){
410 const VertexPair<Graph> uv(*u.first, *nh.first);
411 const VertexPair<Graph> vu(*nh.first, *u.first);
413 if(I.is_matching_edge(uv) == (layer == 0)){
414 for(
size_t j = 0; j < vars.max_multi; ++j) expr += vars.y[i][j].at(uv);
415 DEBUG5(std::cout <<
" + y[" << i <<
"][*]_" << VertexPairAndGraph<Graph>(uv, g));
417 for(
size_t j = 0; j < vars.max_multi; ++j) expr -= vars.y[j][i].at(vu);
418 DEBUG5(std::cout <<
" - y[*]["<<i<<
"]_"<<VertexPairAndGraph<Graph>(vu, g));
423 DEBUG5(std::cout <<
" - y_s["<<i<<
"],"<<VertexAndGraph<Graph>(*u.first, g));
424 expr -= vars.s[i].at(*u.first);
426 DEBUG5(std::cout <<
" + y_"<<VertexAndGraph<Graph>(*u.first, g)<<
",tc["<<i<<
"]");
427 expr += vars.tc[i].at(*u.first);
430 DEBUG5(std::cout <<
" + y_"<<VertexAndGraph<Graph>(*u.first, g)<<
",tp["<<i<<
"]");
431 expr += vars.tp[i].at(*u.first);
438 DEBUG5(std::cout <<
"adding (7): cycle conservation"<<std::endl);
439 for(VertexIterRange<Graph> u = vertices(g); u.first != u.second; ++u.first){
441 for(
size_t i = 0; i < vars.max_multi; ++i) {
442 expr += vars.s[i].at(*u.first);
443 expr -= vars.tc[i].at(*u.first);
454 template<
class Graph>
455 void populate_model(IloModel& model, IloEnv& env, var_collection<Graph>& vars){
456 const Graph& g(*vars.I.g);
457 IloRangeArray c(env);
459 DEBUG3(std::cout <<
"creating variables"<<std::endl);
460 populate_variables(env, vars);
462 DEBUG3(std::cout <<
"creating optimization expression"<<std::endl);
463 IloExpr opt_exp(env);
464 for(EdgeIterRange<Graph> e = boost::edges(g); e.first != e.second; ++e.first){
465 const Vertex<Graph>& u = boost::source(*e.first, g);
466 const Vertex<Graph>& v = boost::target(*e.first, g);
468 auto uv = vars.z.find(std::make_pair(u,v));
469 if(uv == vars.z.end()) uv = vars.z.find(std::make_pair(v,u));
470 assert(uv != vars.z.end());
472 opt_exp += (double)boost::get(boost::edge_weight, g, *e.first) * uv->second;
474 model.add(IloMaximize(env, opt_exp));
476 DEBUG3(std::cout <<
"creating constraints"<<std::endl);
477 populate_constraints(env, c, vars);
Definition: graph_utils.hpp:18
Definition: read_adj_list.hpp:22