9 #include "ilp_common.hpp"
11 #include "utils/profiling.hpp"
18 struct var_collection :
public var_collection_virt<Graph> {
22 var_collection(
const Instance<Graph>& _I):
23 var_collection_virt<Graph>::var_collection_virt(_I) {}
28 class LazyCyclesBlockCallback:
public IloCplex::LazyConstraintCallbackI{
29 const var_collection<Graph>& vars;
30 callback_statistics& stats;
33 IloCplex::CallbackI* duplicateCallback()
const{
34 return (
new (getEnv()) LazyCyclesBlockCallback(getEnv(), vars, stats));
37 LazyCyclesBlockCallback(IloEnv env,
const var_collection<Graph>& _vars, callback_statistics& _stats):
38 IloCplex::LazyConstraintCallbackI(env),
43 void output_current_aux_graph(
const AuxGraph& aux,
const TranslateBiMap<Graph,AuxGraph>& translate)
const;
47 void add_arc_from_variable(
49 const VertexPair<Graph>& uv,
50 const TranslateBiMap<Graph,AuxGraph>& translate,
53 if(is_true(getValue(var))){
54 const Vertex<Graph> u = uv.first;
55 const Vertex<Graph> v = uv.second;
56 const Vertex<AuxGraph> new_u = translate.left.at(u);
57 const Vertex<AuxGraph> new_v = translate.left.at(v);
58 add_edge(new_u, new_v, aux);
59 DEBUG5(std::cout <<
"adding "<<VertexPairAndGraph<Graph>(uv, *vars.I.g)<<std::endl);
60 }
else DEBUG5(std::cout <<
"not adding "<<VertexPairAndGraph<Graph>(uv, *vars.I.g)<<
" since "<<getValue(var)<<
" translates to "<<is_true(getValue(var))<<std::endl);
67 IloCplex::Callback GetLazyCyclesBlock(IloEnv env,
const var_collection<Graph>& vars, callback_statistics& stats) {
68 return (
new (env) LazyCyclesBlockCallback<Graph>(env, vars, stats));
73 void LazyCyclesBlockCallback<Graph>::output_current_aux_graph(
const AuxGraph& aux,
const TranslateBiMap<Graph,AuxGraph>& translate)
const{
74 const Graph& g = *vars.I.g;
75 for(VertexIterRange<AuxGraph> i = vertices(aux); i.first != i.second; ++i.first)
76 if(out_degree(*(i.first), aux) != in_degree(*(i.first), aux)){
77 const Vertex<Graph> u = translate.right.at(*(i.first));
79 std::cout <<
"found vertex "<<VertexAndGraph<Graph>(u, g)<<
" with outdeg = "<< out_degree(*(i.first), aux)<<
" & indeg = "<< in_degree(*(i.first), aux) << std::endl;
80 std::cout <<
"we have: ";
81 if( is_true(getValue(vars.s.at(u)))) std::cout<<
"s ";
82 if( is_true(getValue(vars.tp.at(u)))) std::cout<<
"tp ";
83 if( is_true(getValue(vars.tc.at(u)))) std::cout<<
"tc ";
84 for(VertexIterRange<AuxGraph> j = vertices(aux); j.first != j.second; ++j.first){
85 const Vertex<Graph> v = translate.right.at(*(j.first));
86 VertexPair<Graph> uv(u, v);
87 VertexPair<Graph> vu(v, u);
89 if(contains(vars.y, uv) && is_true(getValue(vars.y.at(uv)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
90 if(contains(vars.y, vu) && is_true(getValue(vars.y.at(vu)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
92 std::cout << std::endl;
94 Vertex<AuxGraph> ux = *(i.first);
95 while(in_degree(ux, aux) > 0){
96 const auto in_edge = in_edges(ux, aux).first;
97 ux = source(*in_edge, aux);
98 std::cout << VertexAndGraph<Graph>(translate.right.at(ux), g)<<
" has indeg "<<in_degree(ux, aux)<<std::endl;
100 while(out_degree(ux, aux) > 0){
101 const auto out_edge = out_edges(ux, aux).first;
102 ux = target(*out_edge, aux);
103 std::cout << VertexAndGraph<Graph>(translate.right.at(ux), g)<<
" has outdeg "<<out_degree(ux, aux)<<std::endl;
110 template<
class Graph>
111 void LazyCyclesBlockCallback<Graph>::main(){
112 stats.time_spent.resume();
115 const Instance<Graph>& I = vars.I;
116 const Graph& g = *I.g;
119 TranslateBiMap<Graph, AuxGraph> translate;
120 typedef typename TranslateBiMap<Graph, AuxGraph>::value_type TranslatePair;
123 std::cout <<
"solution edges: "<<std::endl;
124 for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
125 const Vertex<Graph>& u = source(*e.first, g);
126 const Vertex<Graph>& v = target(*e.first, g);
128 const VertexPair<Graph> uv(u, v);
129 const VertexPair<Graph> vu(v, u);
130 std::cout<<VertexPairAndGraph<Graph>(uv, g)<<
" by ";
131 if(contains(vars.y, uv) && is_true(getValue(vars.y.at(uv)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(uv,g)<<
", ";
132 if(contains(vars.y, vu) && is_true(getValue(vars.y.at(vu)))) std::cout <<
"y_"<<VertexPairAndGraph<Graph>(vu,g)<<
", ";
133 std::cout << std::endl;
138 for( VertexIterRange<Graph> i = vertices(g); i.first != i.second; ++i.first ){
139 const Vertex<Graph> orig_u = *(i.first);
140 const Vertex<AuxGraph> new_u = add_vertex(aux);
141 translate.insert(TranslatePair(orig_u, new_u));
142 DEBUG5(std::cout <<
"adding "<<VertexAndGraph<Graph>(orig_u, g)<<std::endl);
145 DEBUG5(std::cout <<
"adding y arcs"<<std::endl);
146 for(
const auto& i : vars.y ) add_arc_from_variable(i.second, i.first, translate, aux);
149 std::stack<Vertex<AuxGraph> > pending;
150 for(
const auto& i : vars.s )
151 if(is_true(getValue(i.second))) pending.push(translate.left.at(i.first));
154 std::cout<<
"coming from y_s: ";
155 for(
const auto& i : vars.s )
156 if(is_true(getValue(i.second))) std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ";
157 std::cout<<std::endl;
158 std::cout<<
"going to tp: ";
159 for(
const auto& i : vars.tp )
160 if(is_true(getValue(i.second))) std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ";
161 std::cout<< std::endl<<
"going to tc: ";
162 for(
const auto& i : vars.tc )
163 if(is_true(getValue(i.second))) std::cout << VertexAndGraph<Graph>(i.first, g)<<
" ";
164 std::cout<<std::endl;
167 DEBUG2(
unsigned num_p = pending.size();)
169 while(!pending.empty()){
170 const Vertex<AuxGraph> u = pending.top(); pending.pop();
172 const unsigned char deg = out_degree(u, aux);
176 const Edge<AuxGraph> e = *(out_edges(u, aux).first);
177 const Vertex<AuxGraph> v = target(e, aux);
178 DEBUG5(std::cout << VertexAndGraph<Graph>(translate.right.at(v), g) <<
" is on a path by edge from "<<VertexAndGraph<Graph>(translate.right.at(source(e, aux)), g)<<std::endl);
185 DEBUG5(std::cout<<
"remaining arcs in auxilliary graph: "<<num_edges(aux)<<std::endl;);
186 unsigned num_new_cuts = 0;
188 DEBUG5(output_current_aux_graph(aux, translate));
190 #ifdef LAZY_ADD_ALL_CYCLES
191 while(num_edges(aux)){
193 Edge<AuxGraph> uv = *(edges(aux).first);
194 IloExpr expr(getEnv()), rev_expr(getEnv());
197 DEBUG3(std::cout <<
"forbidding cycle: ");
199 const Vertex<AuxGraph> u = source(uv, aux);
200 const Vertex<AuxGraph> v = target(uv, aux);
201 const Vertex<Graph> old_u = translate.right.at(u);
202 const Vertex<Graph> old_v = translate.right.at(v);
203 const VertexPair<Graph> old_uv = VertexPair<Graph>(old_u, old_v);
204 const VertexPair<Graph> old_vu = VertexPair<Graph>(old_v, old_u);
206 DEBUG3(std::cout << VertexPairAndGraph<Graph>(old_uv, g)<<
" ");
207 remove_edge(uv, aux);
208 v_deg = boost::out_degree(v, aux);
211 if(v_deg == 1) uv = *(out_edges(v, aux).first);
214 expr += vars.y.at(old_uv);
215 expr -= vars.tc.at(old_v);
218 expr += vars.y.at(old_vu);
222 DEBUG5(std::cout <<
" by allowing only <"<<count<<
" of its edges (unless it's connected to t_c)");
223 DEBUG3(std::cout << std::endl);
228 #ifdef LAZY_ADD_ALL_CYCLES
233 DEBUG2(std::cout <<
"======= callback called, found "<<num_p<<
" paths & added "<<num_new_cuts<<
" new cuts ======"<<std::endl);
234 stats.times_called++;
235 stats.cuts_added += num_new_cuts;
236 stats.time_spent.pause();
242 template<
class Graph>
243 void populate_variables(IloEnv& env, var_collection<Graph>& vars,
const ilp_options& opts){
244 const Instance<Graph>& I = vars.I;
245 const Graph& g = *I.g;
246 DEBUG5(std::cout <<
"creating x_{u,v}/y_uv"<<std::endl);
247 for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
248 const Vertex<Graph>& u = source(*e.first, g);
249 const Vertex<Graph>& v = target(*e.first, g);
250 const std::string uname = std::to_string(boost::get(boost::vertex_name, g, u));
251 const std::string vname = std::to_string(boost::get(boost::vertex_name, g, v));
254 const std::string xname(
"x_" + uname +
"," + vname);
255 DEBUG5(std::cout <<
"creating "<<xname<<std::endl);
256 vars.x.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, xname.c_str()));
258 const std::string yname1(
"y_" + uname +
"," + vname);
259 const std::string yname2(
"y_" + vname +
"," + uname);
260 DEBUG5(std::cout <<
"creating "<<yname1 <<
" & "<< yname2<<std::endl);
261 vars.y.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, yname1.c_str()));
262 vars.y.emplace(std::piecewise_construct, std::make_tuple(v,u), std::make_tuple(env, 0, 1, IloNumVar::Bool, yname2.c_str()));
264 if(opts.account_for_contig_jumps){
265 const std::string wname1(
"w_" + uname +
"," + vname);
266 const std::string wname2(
"w_" + vname +
"," + uname);
267 DEBUG5(std::cout <<
"creating "<<wname1 <<
" & "<< wname2<<std::endl);
268 vars.w.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, wname1.c_str()));
269 vars.w.emplace(std::piecewise_construct, std::make_tuple(v,u), std::make_tuple(env, 0, 1, IloNumVar::Bool, wname2.c_str()));
272 DEBUG5(std::cout <<
"creating s/tp/tc interaction variables"<<std::endl);
274 for(VertexIterRange<Graph> v = vertices(g); v.first != v.second; ++v.first){
275 const std::string name(std::to_string(
get(vertex_name, g, *v.first)));
277 vars.s[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"y_s," + name).c_str());
279 vars.tp[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"y_" + name +
",tp").c_str());
281 vars.tc[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, (
"y_" + name +
",tc").c_str());
286 template<
class Graph>
287 void populate_constraints(IloEnv& env, IloRangeArray& c,
const var_collection<Graph>& vars,
const ilp_options& opts){
288 const Instance<Graph>& I = vars.I;
289 const Graph& g(*I.g);
292 DEBUG5(std::cout <<
"adding (1): of all the representations of e, exactly x_e should be chosen"<<std::endl);
293 for(
auto x : vars.x){
294 const VertexPair<Graph> uv = x.first;
295 const VertexPair<Graph> vu(uv.second, uv.first);
298 expr += vars.y.at(uv);
299 expr += vars.y.at(vu);
303 if(opts.account_for_contig_jumps){
304 expr += vars.w.at(uv);
305 expr += vars.w.at(vu);
313 DEBUG5(std::cout <<
"adding (2): all matching-edges should be chosen"<<std::endl);
315 if(I.is_matching_edge(x.first)) c.add(x.second == 1);
317 if(opts.limit_paths_and_cycles_individually){
319 DEBUG5(std::cout <<
"adding (4)&(6): there should be at most sigma_p paths & sigma_c cycles"<<std::endl);
320 IloExpr p_expr(env), c_expr(env);
321 for(
auto y : vars.tp) p_expr += y.second;
322 for(
auto y : vars.tc) c_expr += y.second;
323 c.add(p_expr <= (
double)I.num_paths);
324 c.add(c_expr <= (
double)I.num_cycles);
327 DEBUG5(std::cout <<
"adding (4)&(6): there should be at most sigma_p (possibly closed) paths"<<std::endl);
329 for(
auto y : vars.s) expr += y.second;
330 c.add(expr <= (
double)I.num_paths);
334 DEBUG5(std::cout <<
"adding (3): flow conservation"<<std::endl);
335 for(
unsigned layer = 0; layer < 2; ++layer){
336 for(VertexIterRange<Graph> u = boost::vertices(g); u.first != u.second; ++u.first){
338 for(AdjIterRange<Graph> nh = boost::adjacent_vertices(*u.first, g); nh.first != nh.second; ++nh.first){
339 const VertexPair<Graph> uv = std::make_pair(*u.first, *nh.first);
341 if(I.is_matching_edge(uv) == (layer == 0)){
343 expr += vars.y.at(uv);
344 DEBUG5(std::cout <<
" + y_" << VertexPairAndGraph<Graph>(uv, g));
346 const VertexPair<Graph> vu = std::make_pair(*nh.first, *u.first);
348 expr -= vars.y.at(vu);
349 DEBUG5(std::cout <<
" - y_"<<VertexPairAndGraph<Graph>(vu, g));
354 DEBUG5(std::cout <<
" - y_s,"<<VertexAndGraph<Graph>(*u.first, g));
355 expr -= vars.s.at(*u.first);
357 DEBUG5(std::cout <<
" + y_"<<VertexAndGraph<Graph>(*u.first, g)<<
",tc");
358 expr += vars.tc.at(*u.first);
361 DEBUG5(std::cout <<
" + y_"<<VertexAndGraph<Graph>(*u.first, g)<<
",tp");
362 expr += vars.tp.at(*u.first);
369 DEBUG5(std::cout <<
"adding (7): cycle conservation"<<std::endl);
370 for(VertexIterRange<Graph> u = boost::vertices(g); u.first != u.second; ++u.first){
372 expr += vars.s.at(*u.first);
373 expr -= vars.tc.at(*u.first);
381 if(opts.account_for_contig_jumps){
383 DEBUG5(std::cout <<
"adding contig jump constraints"<<std::endl);
384 EdgeExpMap<Graph> expr;
386 #warning TODO: proper handling of contig jumps!
388 for(VertexIterRange<Graph> ur = boost::vertices(g); ur.first != ur.second; ++ur.first){
389 const Vertex<Graph> u(*ur.first);
390 for(AdjIterRange<Graph> vr = boost::adjacent_vertices(u, g); vr.first != vr.second; ++vr.first) {
391 const Vertex<Graph> v(*vr.first);
392 const VertexPair<Graph> uv(u,v);
393 IloExpr uv_expr(env);
395 if(!I.is_matching_edge(uv)){
396 const std::string uname = std::to_string(boost::get(boost::vertex_name, g, u));
397 const std::string vname = std::to_string(boost::get(boost::vertex_name, g, v));
401 for(AdjIterRange<Graph> xr = boost::adjacent_vertices(u, g); xr.first != xr.second; ++xr.first)
if(xr.first != vr.first){
402 const Vertex<Graph> x(*xr.first);
403 const Vertex<Graph> y(I.matched_with(x));
407 const Edge<Graph> e_xy(boost::edge(x, y, g).first);
408 const size_t xy_contig_length = boost::get(boost::edge_length, g, e_xy);
411 if( (xy_contig_length < I.insert_size) && (boost::edge(v, y, g).second) ){
415 const std::string xname = std::to_string(boost::get(boost::vertex_name, g, x));
416 const std::string yname = std::to_string(boost::get(boost::vertex_name, g, y));
417 const std::string pname(
"p_" + uname +
"," + xname +
"," + yname +
"," + vname);
418 DEBUG5(std::cout <<
"creating "<<pname << std::endl);
420 IloNumVar p(env, 0, 1, IloNumVar::Bool, pname.c_str());
424 p_expr += vars.y.at(VertexPair<Graph>(u, x));
426 p_expr += vars.y.at(VertexPair<Graph>(y, v));
437 if( (boost::degree(u, g) == 1) && (boost::degree(v, g) == 2)){
438 const Edge<Graph> e_uv(boost::edge(u, v, g).first);
439 const size_t uv_contig_length = boost::get(boost::edge_length, g, e_uv);
440 if(uv_contig_length < I.insert_size){
444 uv_expr -= vars.w.at(uv);
453 template<
class Graph>
454 void populate_model(IloModel& model, IloEnv& env, var_collection<Graph>& vars,
const ilp_options& opts){
455 const Instance<Graph>& I = vars.I;
456 const Graph& g(*I.g);
457 IloRangeArray c(env);
459 DEBUG3(std::cout <<
"creating variables"<<std::endl);
460 populate_variables(env, vars, opts);
462 DEBUG3(std::cout <<
"creating optimization expression"<<std::endl);
463 IloExpr opt_exp(env);
464 for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
465 const Vertex<Graph>& u = source(*e.first, g);
466 const Vertex<Graph>& v = target(*e.first, g);
468 auto uv = vars.x.find(VertexPair<Graph>(u,v));
469 if(uv == vars.x.end()) uv = vars.x.find(VertexPair<Graph>(v,u));
470 assert(uv != vars.x.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, opts);
Definition: read_adj_list.hpp:22