9 #include "ilp_common.hpp"
11 #include "utils/profiling.hpp"
16 struct var_collection :
public var_collection_virt<Graph> {
18 EdgeVarMap<Graph> y, z, z2;
19 vertex_var_map<Graph> sc;
23 var_collection(
const Instance<Graph>& _I):
24 var_collection_virt<Graph>::var_collection_virt(_I) {}
35 IloCplex::CallbackI* duplicateCallback()
const{
40 IloCplex::LazyConstraintCallbackI(env),
45 void output_current_solution_graph(
const AuxGraph& solution,
const TranslateBiMap<Graph,AuxGraph>& translate)
const;
49 void add_arc_from_variable(
51 const VertexPair<Graph>& uv,
52 const TranslateBiMap<Graph,AuxGraph>& translate,
53 AuxGraph& solution)
const
55 if(is_true(getValue(var))){
56 const Vertex<Graph> u = uv.first;
57 const Vertex<Graph> v = uv.second;
58 const Vertex<AuxGraph> new_u = translate.left.at(u);
59 const Vertex<AuxGraph> new_v = translate.left.at(v);
60 boost::add_edge(new_u, new_v, solution);
61 DEBUG5(std::cout <<
"adding "<<VertexPairAndGraph<Graph>(uv, *vars.I.g)<<std::endl);
62 }
else DEBUG5(std::cout <<
"not adding "<<VertexPairAndGraph<Graph>(uv, *vars.I.g)<<
" since "<<getValue(var)<<
" translates to "<<is_true(getValue(var))<<std::endl);
75 void LazyCyclesBlockCallback<Graph>::output_current_solution_graph(
const AuxGraph& solution,
const TranslateBiMap<Graph,AuxGraph>& translate)
const{
76 const Graph& g = *vars.I.g;
77 for(VertexIterRange<AuxGraph> i = boost::vertices(solution); i.first != i.second; ++i.first)
78 if(boost::out_degree(*(i.first), solution) != boost::in_degree(*(i.first), solution)){
79 const Vertex<Graph> u = translate.right.at(*(i.first));
81 std::cout <<
"found vertex "<<VertexAndGraph<Graph>(u, g)<<
" with outdeg = "<< out_degree(*(i.first), solution)<<
" & indeg = "<< in_degree(*(i.first), solution) << std::endl;
82 std::cout <<
"we have: ";
83 if( is_true(getValue(vars.s.at(u)))) std::cout<<
"s ";
84 if( is_true(getValue(vars.tp.at(u)))) std::cout<<
"tp ";
85 if( is_true(getValue(vars.tc.at(u)))) std::cout<<
"tc ";
86 for(VertexIterRange<AuxGraph> j = vertices(solution); j.first != j.second; ++j.first){
87 const Vertex<Graph> v = translate.right.at(*(j.first));
88 VertexPair<Graph> uv(u, v);
89 VertexPair<Graph> vu(v, u);
91 if(contains(vars.y, uv) && is_true(getValue(vars.y.at(uv)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
92 if(contains(vars.y, vu) && is_true(getValue(vars.y.at(vu)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
93 if(contains(vars.z, uv) && is_true(getValue(vars.z.at(uv)))) std::cout <<
"z_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
94 if(contains(vars.z, vu) && is_true(getValue(vars.z.at(vu)))) std::cout <<
"z_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
95 if(contains(vars.z2, uv) && is_true(getValue(vars.z2.at(uv)))) std::cout <<
"z'_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
96 if(contains(vars.z2, vu) && is_true(getValue(vars.z2.at(vu)))) std::cout <<
"z'_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
98 std::cout << std::endl;
100 Vertex<AuxGraph> ux = *(i.first);
101 while(boost::in_degree(ux, solution) > 0){
102 const Edge<AuxGraph>& in_edge = *(boost::in_edges(ux, solution).first);
103 ux = boost::source(in_edge, solution);
104 std::cout << VertexAndGraph<Graph>(translate.right.at(ux), g)<<
" has indeg "<<boost::in_degree(ux, solution)<<std::endl;
106 while(boost::out_degree(ux, solution) > 0){
107 const Edge<AuxGraph>& out_edge = *(boost::out_edges(ux, solution).first);
108 ux = target(out_edge, solution);
109 std::cout << VertexAndGraph<Graph>(translate.right.at(ux), g)<<
" has outdeg "<<boost::out_degree(ux, solution)<<std::endl;
115 template<
class Graph>
116 void LazyCyclesBlockCallback<Graph>::main(){
117 stats.time_spent.resume();
120 const Instance<Graph>& I = vars.I;
121 const Graph& g = *I.g;
124 std::cout <<
"solution edges: "<<std::endl;
125 for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
126 const Vertex<Graph>& u = boost::source(*e.first, g);
127 const Vertex<Graph>& v = boost::target(*e.first, g);
129 const VertexPair<Graph> uv(u, v);
130 const VertexPair<Graph> vu(v, u);
131 std::cout<<VertexPairAndGraph<Graph>(uv, g)<<
" by ";
133 if(contains(vars.y, uv) && is_true(getValue(vars.y.at(uv)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
134 if(contains(vars.y, vu) && is_true(getValue(vars.y.at(vu)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
135 if(contains(vars.z, uv) && is_true(getValue(vars.z.at(uv)))) std::cout <<
"z_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
136 if(contains(vars.z, vu) && is_true(getValue(vars.z.at(vu)))) std::cout <<
"z_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
137 if(contains(vars.z2, uv) && is_true(getValue(vars.z2.at(uv)))) std::cout <<
"z'_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
138 if(contains(vars.z2, vu) && is_true(getValue(vars.z2.at(vu)))) std::cout <<
"z'_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
139 std::cout << std::endl;
144 TranslateBiMap<Graph, AuxGraph> translate;
145 typedef typename TranslateBiMap<Graph, AuxGraph>::value_type TranslatePair;
148 for( VertexIterRange<Graph> i = boost::vertices(g); i.first != i.second; ++i.first ){
149 const Vertex<Graph> orig_u = *(i.first);
150 const Vertex<AuxGraph> new_u = boost::add_vertex(solution);
151 translate.insert(TranslatePair(orig_u, new_u));
152 DEBUG5(std::cout <<
"adding "<<VertexAndGraph<Graph>(orig_u, g)<<std::endl);
155 DEBUG5(std::cout <<
"adding y arcs"<<std::endl);
156 for(
const auto& i : vars.y )
157 add_arc_from_variable(i.second, i.first, translate, solution);
158 DEBUG5(std::cout <<
"adding z arcs"<<std::endl);
159 for(
const auto& i : vars.z )
160 add_arc_from_variable(i.second, i.first, translate, solution);
161 DEBUG5(std::cout <<
"adding z' arcs"<<std::endl);
162 for(
const auto& i : vars.z2 )
163 add_arc_from_variable(i.second, i.first, translate, solution);
166 std::stack<Vertex<AuxGraph> > pending;
167 DEBUG5(std::cout<<
"coming from s: ");
168 for(
const auto& i : vars.s )
169 if(is_true(getValue(i.second))) {
170 DEBUG5(std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ");
171 pending.push(translate.left.at(i.first));
173 DEBUG5(std::cout<<std::endl);
175 DEBUG5(std::cout<<
"coming from sc: ");
176 for(
const auto& i : vars.sc )
177 if(is_true(getValue(i.second))) {
178 DEBUG5(std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ");
179 pending.push(translate.left.at(i.first));
181 DEBUG5(std::cout<<std::endl);
183 DEBUG5(std::cout<<
"going to tp: ";
184 for(
const auto& i : vars.tp )
185 if(is_true(getValue(i.second))) std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ";
186 std::cout<< std::endl<<
"going to tc: ";
187 for(
const auto& i : vars.tc )
188 if(is_true(getValue(i.second))) std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ";
189 std::cout<<std::endl;
193 DEBUG2(
const unsigned num_p = pending.size();)
195 while(!pending.empty()){
196 const Vertex<AuxGraph> u = pending.top(); pending.pop();
198 const unsigned char deg = boost::out_degree(u, solution);
202 const Edge<AuxGraph> e = *(boost::out_edges(u, solution).first);
203 const Vertex<AuxGraph> v = boost::target(e, solution);
204 DEBUG5(std::cout << VertexAndGraph<Graph>(translate.right.at(v), g) <<
" is on a path by edge from "<<VertexAndGraph<Graph>(translate.right.at(source(e, solution)), g)<<std::endl);
206 boost::remove_edge(e, solution);
211 DEBUG5(std::cout<<
"remaining arcs in auxilliary graph: "<<num_edges(solution)<<std::endl;);
212 unsigned num_new_cuts = 0;
213 if(num_edges(solution)){
214 DEBUG5(output_current_solution_graph(solution, translate));
216 #ifdef LAZY_ADD_ALL_CYCLES
217 while(num_edges(solution)){
219 std::stack<Edge<AuxGraph> > e_pending;
220 e_pending.push(*(edges(solution).first));
221 IloExpr p_expr(getEnv()), rev_p_expr(getEnv());
222 IloExpr c_expr(getEnv()), rev_c_expr(getEnv());
224 DEBUG3(std::cout <<
"forbidding cycle: ");
225 while(!e_pending.empty()){
226 const Edge<AuxGraph> e = e_pending.top(); e_pending.pop();
227 const Vertex<AuxGraph> u = boost::source(e, solution);
228 const Vertex<AuxGraph> v = boost::target(e, solution);
229 const Vertex<Graph> old_u = translate.right.at(u);
230 const Vertex<Graph> old_v = translate.right.at(v);
231 const VertexPair<Graph> old_uv = VertexPair<Graph>(old_u, old_v);
232 const VertexPair<Graph> old_vu = VertexPair<Graph>(old_v, old_u);
234 DEBUG3(std::cout << VertexPairAndGraph<Graph>(old_uv, g)<<
" ");
235 boost::remove_edge(e, solution);
236 const unsigned char v_deg = boost::out_degree(v, solution);
239 if(v_deg == 1) e_pending.push(*(out_edges(v, solution).first));
242 p_expr += vars.y.at(old_uv);
243 c_expr += vars.z.at(old_uv);
245 rev_p_expr += vars.y.at(old_vu);
246 rev_c_expr += vars.z.at(old_vu);
250 DEBUG5(std::cout <<
" by allowing only <"<<count<<
" of its edges");
251 DEBUG3(std::cout << std::endl);
254 add(rev_p_expr < count);
255 add(rev_c_expr < count);
257 #ifdef LAZY_ADD_ALL_CYCLES
262 DEBUG2(std::cout <<
"======= callback called, found "<<num_p<<
" paths & added "<<num_new_cuts<<
" new cuts ======"<<std::endl);
263 stats.times_called++;
264 stats.cuts_added += num_new_cuts;
265 stats.time_spent.pause();
270 template<
class Graph>
271 void create_edge_variable(
273 EdgeVarMap<Graph>& x,
274 const IloNumVar::Type& Type,
275 const size_t lower_bnd,
276 const size_t upper_bnd,
278 const Vertex<Graph>& u,
279 const Vertex<Graph>& v,
280 const std::string& prefix)
282 const std::string uname = std::to_string(boost::get(boost::vertex_name, g, u));
283 const std::string vname = std::to_string(boost::get(boost::vertex_name, g, v));
284 const std::string full_name(prefix + uname +
"," + vname);
285 DEBUG5(std::cout <<
"creating "<<full_name<<std::endl);
286 x.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, lower_bnd, upper_bnd, Type, full_name.c_str()));
291 template<
class Graph>
292 void populate_variables(IloEnv& env, var_collection<Graph>& vars){
293 const Instance<Graph>& I = vars.I;
294 const Graph& g = *I.g;
295 DEBUG5(std::cout <<
"creating x_{u,v}/y_uv"<<std::endl);
296 for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
297 const Vertex<Graph>& u = source(*e.first, g);
298 const Vertex<Graph>& v = target(*e.first, g);
299 const std::string uname = std::to_string(
get(vertex_name, g, u));
300 const std::string vname = std::to_string(
get(vertex_name, g, v));
303 create_edge_variable(env, vars.x, IloNumVar::Bool, 0, 1, g, u, v,
"x_");
305 create_edge_variable(env, vars.y, IloNumVar::Bool, 0, 1, g, u, v,
"y_");
306 create_edge_variable(env, vars.y, IloNumVar::Bool, 0, 1, g, v, u,
"y_");
309 create_edge_variable(env, vars.z, IloNumVar::Bool, 0, 1, g, u, v,
"z_");
310 create_edge_variable(env, vars.z, IloNumVar::Bool, 0, 1, g, v, u,
"z_");
311 if(!I.is_matching_edge(u, v)){
313 create_edge_variable(env, vars.z2, IloNumVar::Bool, 0, 1, g, u, v,
"z'_");
314 create_edge_variable(env, vars.z2, IloNumVar::Bool, 0, 1, g, v, u,
"z'_");
317 DEBUG5(std::cout <<
"creating s/tp/tc interaction variables"<<std::endl);
319 for(VertexIterRange<Graph> v = vertices(g); v.first != v.second; ++v.first){
320 const std::string name(std::to_string(
get(vertex_name, g, *v.first)));
322 vars.s[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"y_s," + name).c_str());
323 vars.sc[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"z_s," + name).c_str());
325 vars.tp[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"y_" + name +
",tp").c_str());
327 vars.tc[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"z_" + name +
",tc").c_str());
332 template<
class Graph>
333 void populate_constraints(IloEnv& env, IloRangeArray& c,
const var_collection<Graph>& vars){
334 const Instance<Graph>& I = vars.I;
335 const Graph& g(*I.g);
338 DEBUG5(std::cout <<
"adding (1): of all the representations of e, exactly x_e should be chosen"<<std::endl);
339 for(
auto x : vars.x){
340 const VertexPair<Graph>& uv = x.first;
341 const VertexPair<Graph> vu(uv.second, uv.first);
342 const unsigned layer = I.is_matching_edge(uv) ? 0 : 1;
345 expr += vars.y.at(uv);
346 expr += vars.y.at(vu);
348 expr += vars.z.at(uv);
349 expr += vars.z.at(vu);
351 expr += vars.z2.at(uv);
352 expr += vars.z2.at(vu);
359 DEBUG5(std::cout <<
"adding (2): all matching-edges should be chosen"<<std::endl);
361 if(I.is_matching_edge(x.first)) c.add(x.second == 1);
364 DEBUG5(std::cout <<
"adding (4)&(6): there should be at most sigma_p paths & sigma_c cycles"<<std::endl);
366 IloExpr p_expr(env), c_expr(env);
367 for(
auto y : vars.tp) p_expr += y.second;
368 for(
auto y : vars.tc) c_expr += y.second;
369 c.add(p_expr <= (
double)I.num_paths);
370 c.add(c_expr <= (
double)I.num_cycles);
374 DEBUG5(std::cout <<
"adding (3): flow conservation"<<std::endl);
375 for(
unsigned layer = 0; layer < 2; ++layer){
376 for(VertexIterRange<Graph> u = boost::vertices(g); u.first != u.second; ++u.first){
377 IloExpr p_expr(env), c_expr(env);
378 for(AdjIterRange<Graph> nh = boost::adjacent_vertices(*u.first, g); nh.first != nh.second; ++nh.first){
379 const VertexPair<Graph> uv(*u.first, *nh.first);
381 if(I.is_matching_edge(uv) == (layer == 0)){
383 DEBUG5(std::cout <<
" + y_" << VertexPairAndGraph<Graph>(uv, g));
384 p_expr += vars.y.at(uv);
385 c_expr += vars.z.at(uv);
388 if(layer == 1) c_expr += vars.z2.at(uv);
390 const VertexPair<Graph> vu(*nh.first, *u.first);
392 DEBUG5(std::cout <<
" - y_"<<VertexPairAndGraph<Graph>(vu, g));
393 p_expr -= vars.y.at(vu);
394 c_expr -= vars.z.at(vu);
400 DEBUG5(std::cout <<
" - y_s,"<<VertexAndGraph<Graph>(*u.first, g));
401 p_expr -= vars.s.at(*u.first);
402 c_expr -= vars.sc.at(*u.first);
405 DEBUG5(std::cout <<
" + y_"<<VertexAndGraph<Graph>(*u.first, g)<<
",tp");
406 p_expr += vars.tp.at(*u.first);
410 DEBUG5(std::cout <<
" == 0"<< std::endl);
414 for(VertexIterRange<Graph> u = boost::vertices(g); u.first != u.second; ++u.first){
416 for(AdjIterRange<Graph> nh = boost::adjacent_vertices(*u.first, g); nh.first != nh.second; ++nh.first){
417 const VertexPair<Graph> vu(*nh.first, *u.first);
418 if(!I.is_matching_edge(vu)){
419 DEBUG5(std::cout <<
" - z'_"<<VertexPairAndGraph<Graph>(vu, g));
420 c_expr -= vars.z2.at(vu);
424 DEBUG5(std::cout <<
" + z_"<<VertexAndGraph<Graph>(*u.first, g)<<
",tc");
425 c_expr += vars.tc.at(*u.first);
426 DEBUG5(std::cout <<
" == 0" << std::endl);
432 DEBUG5(std::cout <<
"adding (7): cycle conservation"<<std::endl);
433 for(VertexIterRange<Graph> u = vertices(g); u.first != u.second; ++u.first){
435 expr += vars.sc.at(*u.first);
436 expr -= vars.tc.at(*u.first);
447 template<
class Graph>
448 void populate_model(IloModel& model, IloEnv& env, var_collection<Graph>& vars){
449 const Instance<Graph>& I = vars.I;
450 const Graph& g(*I.g);
451 IloRangeArray c(env);
453 DEBUG3(std::cout <<
"creating variables"<<std::endl);
454 populate_variables(env, vars);
456 DEBUG3(std::cout <<
"creating optimization expression"<<std::endl);
457 IloExpr opt_exp(env);
458 for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
459 const Vertex<Graph>& u = source(*e.first, g);
460 const Vertex<Graph>& v = target(*e.first, g);
462 auto uv = vars.x.find(std::make_pair(u,v));
463 if(uv == vars.x.end()) uv = vars.x.find(std::make_pair(v,u));
464 assert(uv != vars.x.end());
466 opt_exp += (double)boost::get(boost::edge_weight, g, *e.first) * uv->second;
468 model.add(IloMaximize(env, opt_exp));
470 DEBUG3(std::cout <<
"creating constraints"<<std::endl);
471 populate_constraints(env, c, vars);
Definition: ilp_model_3layers.hpp:30
Definition: ilp_common.hpp:40
Definition: read_adj_list.hpp:22
Definition: ilp_model.hpp:25