Scaffolding  0.1
This program can assemble genome scaffolds using the pairing information in paired-end reads.
ilp_model_new.hpp
1 
2 
3 #ifndef ILP_MODEL_HPP
4 #define ILP_MODEL_HPP
5 
6 #include <time.h>
7 #include <string>
8 #include <vector>
9 
10 #include <boost/bimap.hpp>
11 #include <boost/bimap/unordered_set_of.hpp>
12 
13 #include <ilcplex/ilocplex.h>
14 
15 #include "utils/utils.hpp"
16 #include "utils/graph_typedefs.hpp"
17 
18 
19 #define is_true(x) (lround(x))
20 
21 // if LAZY_ADD_ALL_CYCLES is defined, then all cycles in the solution returned by CPLEX are added by the lazy callback
22 // otherwise, just the first cycle is added
23 #define LAZY_ADD_ALL_CYCLES
24 
25 namespace scaffold{
26 
27  struct callback_statistics {
28  double time_spent;
29  unsigned cuts_added;
30  unsigned times_called;
31 
32  callback_statistics(): time_spent(0.0), cuts_added(0), times_called(0) {}
33  };
34 
35 
36  // a mapping of edges to variables
37  template<class Graph>
38  using EdgeVarMap = unordered_map<VertexPair<Graph>, IloNumVar, pair_hash<Vertex<Graph>,Vertex<Graph> > >;
39  // a mapping of vertices to variables
40  template<class Graph>
41  using vertex_var_map = unordered_map<Vertex<Graph>, IloNumVar>;
42 
43  template<class Graph>
44  struct var_collection{
45  const Graph& g;
46  EdgeVarMap<Graph> x;
47  EdgeVarMap<Graph> y[2];
48  EdgeVarMap<Graph> z[3]; // z[0] = layer 0 -> layer 1, z[1] = layer 1 -> layer 0, z[2] = layer 1 -> layer 2
49  vertex_var_map<Graph> ys, yt, zs, zt;
50 
51  var_collection(const Graph& _g): g(_g) {}
52  };
53 
54  // auxiliary graph for callback construction
55  typedef adjacency_list<hash_setS,
56  listS,
57  bidirectionalS,
58  no_property,
59  no_property
60  > AuxGraph;
61 
62 
63  template<class GraphA, class GraphB>
64  using TranslateMap = boost::bimap< boost::bimaps::unordered_set_of<Vertex<GraphA> >, boost::bimaps::unordered_set_of<Vertex<GraphB> > >;
65 
66 
67  // block isolated cycles as lazy constraint callback
68  template<class Graph>
69  class LazyCyclesBlockCallback: public IloCplex::LazyConstraintCallbackI{
70  const var_collection<Graph>& vars;
71  callback_statistics& stats;
72  public:
73 
74  IloCplex::CallbackI* duplicateCallback() const{
75  return (new (getEnv()) LazyCyclesBlockCallback(getEnv(), vars, stats));
76  }
77 
78  LazyCyclesBlockCallback(IloEnv env, const var_collection<Graph>& _vars, callback_statistics& _stats):
79  IloCplex::LazyConstraintCallbackI(env),
80  vars(_vars),
81  stats(_stats)
82  {}
83 
84  void main();
85 
86  // adds an arc to the auxiliary graph, given an IloNumVar and a VertexPair
87  void add_arc_from_variable(
88  const IloNumVar& var,
89  const VertexPair<Graph>& uv,
90  const TranslateMap<Graph,AuxGraph>& translate,
91  AuxGraph& aux) const
92  {
93  if(is_true(getValue(var))){
94  const Vertex<Graph> u = uv.first;
95  const Vertex<Graph> v = uv.second;
96  const Vertex<AuxGraph> new_u = translate.left.at(u);
97  const Vertex<AuxGraph> new_v = translate.left.at(v);
98  add_edge(new_u, new_v, aux);
99  DEBUG5(std::cout << "adding "<<VertexPairAndGraph<Graph>(uv, vars.g)<<std::endl);
100  } else DEBUG5(std::cout << "not adding "<<VertexPairAndGraph<Graph>(uv, vars.g)<< " since "<<getValue(var)<<" translates to "<<is_true(getValue(var))<<std::endl);
101  }
102 
103  // add the variable corresponding to the given VertexPair to the given expression
104  void add_corresponding_variable(const EdgeVarMap<Graph> varmap[], const VertexPair<Graph>& uv, IloExpr& exp) const{
105  if(contains(varmap[0], uv))
106  exp += varmap[0].at(uv);
107  else
108  exp += varmap[1].at(uv);
109  }
110 
111 
112  }; // class
113 
114  // callback function
115  template<class Graph>
116  IloCplex::Callback GetLazyCyclesBlock(IloEnv env, const var_collection<Graph>& vars, callback_statistics& stats) {
117  return (new (env) LazyCyclesBlockCallback<Graph>(env, vars, stats));
118  }
119 
120 
121 
122  template<class Graph>
123  void LazyCyclesBlockCallback<Graph>::main(){
124  time_t start_time = clock();
125  AuxGraph aux;
126 
127  // Step 1: construct auxiliary graph
128  TranslateMap<Graph, AuxGraph> translate;
129  typedef typename TranslateMap<Graph, AuxGraph>::value_type TranslatePair;
130 
131 
132 
133  DEBUG5(
134  std::cout << "solution edges: "<<std::endl;
135  for(EdgeIterRange<Graph> e = edges(vars.g); e.first != e.second; ++e.first){
136  const Vertex<Graph>& u = source(*e.first, vars.g);
137  const Vertex<Graph>& v = target(*e.first, vars.g);
138  // get the appropriate x_ij variable
139  const VertexPair<Graph> uv(u, v);
140  const VertexPair<Graph> vu(v, u);
141  std::cout<<VertexPairAndGraph<Graph>(uv, vars.g)<<" by ";for(unsigned l = 0; l < 3; ++l){
142  if(l < 2){
143  if(contains(vars.y[l], uv) && is_true(getValue(vars.y[l].at(uv)))) std::cout << "y["<<l<<"]_"<<VertexPairAndGraph<Graph>(uv,vars.g)<<", ";
144  if(contains(vars.y[l], vu) && is_true(getValue(vars.y[l].at(vu)))) std::cout << "y["<<l<<"]_"<<VertexPairAndGraph<Graph>(vu,vars.g)<<", ";
145  }
146  if(contains(vars.z[l], uv) && is_true(getValue(vars.z[l].at(uv)))) std::cout << "z["<<l<<"]_"<<VertexPairAndGraph<Graph>(uv,vars.g)<<", ";
147  if(contains(vars.z[l], vu) && is_true(getValue(vars.z[l].at(vu)))) std::cout << "z["<<l<<"]_"<<VertexPairAndGraph<Graph>(vu,vars.g)<<", ";
148  std::cout << std::endl;
149  }
150  }
151  );
152 
153 
154 
155 
156  // create vertices
157  for( VertexIterRange<Graph> i = vertices(vars.g); i.first != i.second; ++i.first ){
158  const Vertex<Graph> orig_u = *(i.first);
159  const Vertex<AuxGraph> new_u = add_vertex(aux);
160  translate.insert(TranslatePair(orig_u, new_u));
161  DEBUG5(std::cout << "adding "<<VertexAndGraph<Graph>(orig_u, vars.g)<<std::endl);
162  }
163  // create arcs, merging y-arcs and z-arcs into one auxilliary digraph
164  for(unsigned char j = 0; j < 2; ++j) {
165  DEBUG5(std::cout << "adding y-layer-"<<(int)j<<" --> y-layer-"<<(int)(j+1)%2<<" arcs"<<std::endl);
166  for( const auto& i : vars.y[j] ) add_arc_from_variable(i.second, i.first, translate, aux);
167  }
168  for(unsigned char j = 0; j < 3; ++j) {
169  DEBUG5(if(j<2) std::cout << "adding z-layer-"<<(int)j<<" --> z-layer-"<<(int)(j+1)%2<<" arcs"<<std::endl);
170  DEBUG5(if(j==2) std::cout << "adding z-layer-1 --> z-layer-2 arcs"<<std::endl);
171  for( const auto& i : vars.z[j] ) add_arc_from_variable(i.second, i.first, translate, aux);
172  }
173 
174  // Step 2: remove all arcs reachable from s
175  std::stack<Vertex<AuxGraph> > pending;
176  DEBUG5(std::cout<<"coming from y_s: ");
177  for( const auto& i : vars.ys )
178  if(is_true(getValue(i.second))) {
179  DEBUG5(std::cout << VertexAndGraph<Graph>(i.first, vars.g)<<" ");
180  pending.push(translate.left.at(i.first));
181  }
182  DEBUG5(std::cout<< std::endl<<"coming from z_s: ");
183  for( const auto& i : vars.zs )
184  if(is_true(getValue(i.second))) {
185  DEBUG5(std::cout << VertexAndGraph<Graph>(i.first, vars.g)<<" ");
186  pending.push(translate.left.at(i.first));
187  }
188  DEBUG5(std::cout<<std::endl);
189  DEBUG5(std::cout<<"going to y_t: ");
190  for( const auto& i : vars.yt )
191  if(is_true(getValue(i.second))) {
192  DEBUG5(std::cout << VertexAndGraph<Graph>(i.first, vars.g)<<" ");
193  }
194  DEBUG5(std::cout<< std::endl<<"going to z_t: ");
195  for( const auto& i : vars.zt )
196  if(is_true(getValue(i.second))) {
197  DEBUG5(std::cout << VertexAndGraph<Graph>(i.first, vars.g)<<" ");
198  }
199  DEBUG5(std::cout<<std::endl);
200 
201  unsigned num_p = pending.size();
202 
203  while(!pending.empty()){
204  const Vertex<AuxGraph> u = pending.top(); pending.pop();
205  // note that u has an incoming arc y_s -> u, so, by flow conservation, it has only 1 outgoing arc
206  const unsigned char deg = out_degree(u, aux);
207  assert(deg <= 1);
208  // if this outgoing arc is not to y_t, then add the next vertex to pending & remove the arc
209  if(deg == 1) {
210  const Edge<AuxGraph> e = *(out_edges(u, aux).first);
211  const Vertex<AuxGraph> v = target(e, aux);
212  DEBUG5(std::cout << VertexAndGraph<Graph>(translate.right.at(v), vars.g) << " is on a path by edge from "<<VertexAndGraph<Graph>(translate.right.at(source(e, aux)), vars.g)<<std::endl);
213  pending.push(v);
214  remove_edge(e, aux);
215  }
216  }
217 
218  // Step 3: find a cycle in the remaining part of the graph
219  DEBUG5(std::cout<< "remaining arcs in auxilliary graph: "<<num_edges(aux)<<std::endl;);
220  unsigned num_new_cuts = 0;
221  if(num_edges(aux)){
222  DEBUG5(
223  for(VertexIterRange<AuxGraph> i = vertices(aux); i.first != i.second; ++i.first)
224  if(out_degree(*(i.first), aux) != in_degree(*(i.first), aux)){
225  const Vertex<Graph> u = translate.right.at(*(i.first));
226 
227  std::cout << "found vertex "<<VertexAndGraph<Graph>(u, vars.g)<<" with outdeg = "<< out_degree(*(i.first), aux)<<" & indeg = "<< in_degree(*(i.first), aux) << std::endl;
228  std::cout << "we have: ";
229  if( is_true(getValue(vars.ys.at(u)))) std::cout<<"ys ";
230  if( is_true(getValue(vars.yt.at(u)))) std::cout<<"yt ";
231  if( is_true(getValue(vars.zs.at(u)))) std::cout<<"zs ";
232  if( is_true(getValue(vars.zt.at(u)))) std::cout<<"zt ";
233  for(VertexIterRange<AuxGraph> j = vertices(aux); j.first != j.second; ++j.first){
234  const Vertex<Graph> v = translate.right.at(*(j.first));
235  VertexPair<Graph> uv(u, v);
236  VertexPair<Graph> vu(v, u);
237 
238  for(unsigned l = 0; l < 3; ++l){
239  if(l < 2){
240  if(contains(vars.y[l], uv) && is_true(getValue(vars.y[l].at(uv)))) std::cout << "y["<<l<<"]_"<<VertexPairAndGraph<Graph>(uv,vars.g)<<", ";
241  if(contains(vars.y[l], vu) && is_true(getValue(vars.y[l].at(vu)))) std::cout << "y["<<l<<"]_"<<VertexPairAndGraph<Graph>(vu,vars.g)<<", ";
242  }// if
243  if(contains(vars.z[l], uv) && is_true(getValue(vars.z[l].at(uv)))) std::cout << "z["<<l<<"]_"<<VertexPairAndGraph<Graph>(uv,vars.g)<<", ";
244  if(contains(vars.z[l], vu) && is_true(getValue(vars.z[l].at(vu)))) std::cout << "z["<<l<<"]_"<<VertexPairAndGraph<Graph>(vu,vars.g)<<", ";
245  }// for
246  }// for
247  std::cout << std::endl;
248 
249  Vertex<AuxGraph> ux = *(i.first);
250  while(in_degree(ux, aux) > 0){
251  const auto in_edge = in_edges(ux, aux).first;
252  ux = source(*in_edge, aux);
253  std::cout << VertexAndGraph<Graph>(translate.right.at(ux), vars.g)<< " has indeg "<<in_degree(ux, aux)<<std::endl;
254  }
255  while(out_degree(ux, aux) > 0){
256  const auto out_edge = out_edges(ux, aux).first;
257  ux = target(*out_edge, aux);
258  std::cout << VertexAndGraph<Graph>(translate.right.at(ux), vars.g)<< " has outdeg "<<out_degree(ux, aux)<<std::endl;
259  }
260 
261  exit(1);
262  }// if & for
263  );
264 
265 #ifdef LAZY_ADD_ALL_CYCLES
266  while(num_edges(aux)){
267 #endif
268  std::stack<Edge<AuxGraph> > e_pending;
269  e_pending.push(*(edges(aux).first));
270  IloExpr y_expr(getEnv()), z_expr(getEnv()), y_rev_expr(getEnv()), z_rev_expr(getEnv());
271  unsigned count = 0;
272  DEBUG3(std::cout << "forbidding cycle: ");
273  while(!e_pending.empty()){
274  const Edge<AuxGraph> e = e_pending.top(); e_pending.pop();
275  const Vertex<AuxGraph> u = source(e, aux);
276  const Vertex<AuxGraph> v = target(e, aux);
277  const Vertex<AuxGraph> old_u = translate.right.at(u);
278  const Vertex<AuxGraph> old_v = translate.right.at(v);
279  const VertexPair<Graph> old_uv = VertexPair<Graph>(old_u, old_v);
280  const VertexPair<Graph> old_vu = VertexPair<Graph>(old_v, old_u);
281  DEBUG3(std::cout << VertexPairAndGraph<Graph>(old_uv, vars.g)<<" ");
282  remove_edge(e, aux);
283  const unsigned char deg = out_degree(v, aux);
284  assert(deg <= 1);
285  // if this outgoing arc is not to our initial arc, then add the next vertex to pending & remove the arc
286  if(deg == 1) e_pending.push(*(out_edges(v, aux).first));
287  // forbid the cycle and its reverse in y and z
288  add_corresponding_variable(vars.y, old_uv, y_expr);
289  add_corresponding_variable(vars.y, old_vu, y_rev_expr);
290  add_corresponding_variable(vars.z, old_uv, z_expr);
291  add_corresponding_variable(vars.z, old_vu, z_rev_expr);
292  ++count;
293  }
294  DEBUG5(std::cout << " by allowing only <"<<count<<" of its edges");
295  DEBUG3(std::cout << std::endl);
296  add(y_expr < count);
297  add(z_expr < count);
298  add(y_rev_expr < count);
299  add(z_rev_expr < count);
300  ++num_new_cuts;
301 #ifdef LAZY_ADD_ALL_CYCLES
302  }// while(num_edges(aux))
303 #endif
304  }// if(num_edges(aux))
305  // Step 4: collect statistical information
306  DEBUG2(std::cout << "======= callback called, found "<<num_p<<" paths & added "<<num_new_cuts<<" new cuts ======"<<std::endl);
307  stats.times_called++;
308  stats.cuts_added += num_new_cuts;
309  stats.time_spent += ( (double)(clock() - start_time))/CLOCKS_PER_SEC;
310  } // main()
311 
312 
313 
314  // initialize the variables for the ILP formulation
315  template<class Graph>
316  void populate_variables(IloEnv& env, var_collection<Graph>& vars, const Instance<Graph>& I){
317  Graph& g = *I.g;
318  DEBUG5(std::cout << "creating x_ij/y_ij/z_ij"<<std::endl);
319  // Step 1: add variables x_ij = 1 <=> ij belogs to a path/cycle
320  for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
321  const Vertex<Graph>& u = source(*e.first, g);
322  const Vertex<Graph>& v = target(*e.first, g);
323  const std::string uname = std::to_string(get(vertex_name, g, u));
324  const std::string vname = std::to_string(get(vertex_name, g, v));
325  const std::string name("x_" + uname + "," + vname);
326  DEBUG5(std::cout << "creating "<<name<<std::endl);
327  vars.x.emplace(std::piecewise_construct, std::make_tuple(u, v), std::make_tuple(env, 0, 1, IloNumVar::Bool, name.c_str()));
328  // use matching edges only iff we're between layers 0 & 1
329  for(unsigned k = 0; k < 3; ++k) if( I.is_matching_edge(*e.first) == (k == 0)){
330  const std::string yname_uv( "y^" + std::to_string(k) + "_" + uname + "," + vname);
331  const std::string yname_vu( "y^" + std::to_string(k) + "_" + vname + "," + uname);
332  const std::string zname_uv( "z^" + std::to_string(k) + "_" + uname + "," + vname);
333  const std::string zname_vu( "z^" + std::to_string(k) + "_" + vname + "," + uname);
334 
335  if(k < 2){
336  EdgeVarMap<Graph>& yk_map = vars.y[k];
337  // Step 2: add variables y^k_ij
338  yk_map.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, yname_uv.c_str()));
339  yk_map.emplace(std::piecewise_construct, std::make_tuple(v,u), std::make_tuple(env, 0, 1, IloNumVar::Bool, yname_vu.c_str()));
340  }
341  EdgeVarMap<Graph>& zk_map = vars.z[k];
342  // Step 3: add variables z^l_ij
343  zk_map.emplace(std::piecewise_construct, std::make_tuple(u,v), std::make_tuple(env, 0, 1, IloNumVar::Bool, zname_uv.c_str()));
344  zk_map.emplace(std::piecewise_construct, std::make_tuple(v,u), std::make_tuple(env, 0, 1, IloNumVar::Bool, zname_vu.c_str()));
345  }
346  }
347  DEBUG5(std::cout << "creating sp/tp/sc/tc interaction variables"<<std::endl);
348  // Step 4: add variables y^0_sp,i and y^n_i,tp (and the z-versions)
349  for(VertexIterRange<Graph> v = vertices(g); v.first != v.second; ++v.first){
350  const std::string name(std::to_string(get(vertex_name, g, *v.first)));
351  // on layer 0, come up from sp
352  vars.ys[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, ("y_sp," + name).c_str());
353  // on layer 1, go up to tp
354  vars.yt[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, ("y_" + name + ",tp").c_str());
355  // on layer 0, come up from sc
356  vars.zs[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, ("z_sc," + name).c_str());
357  // on layer 2, go up to tc
358  vars.zt[*v.first] = IloNumVar(env, 0, 1, IloNumVar::Bool, ("z_" + name + ",tc").c_str());
359  }
360  }
361 
362  // initialize the constraints for the ILP formulation
363  template<class Graph>
364  void populate_constraints(IloEnv& env, IloRangeArray& c, const var_collection<Graph>& vars, const Instance<Graph>& I){
365  const Graph& g(*I.g);
366 
367  // constraint (27): of all the representations of ij, exactly x_ij should be chosen!
368  DEBUG5(std::cout << "adding (27): of all the representations of ij, exactly x_ij should be chosen"<<std::endl);
369  for(auto x : vars.x){
370  const VertexPair<Graph> uv = x.first;
371  const VertexPair<Graph> vu(uv.second, uv.first);
372 
373  IloExpr expr(env);
374  for(size_t l = 0; l < 3; ++l) if( I.is_matching_edge(uv) == (l == 0)){
375  if(l < 2){
376  expr += vars.y[l].at(uv);
377  expr += vars.y[l].at(vu);
378  }
379  expr += vars.z[l].at(uv);
380  expr += vars.z[l].at(vu);
381  }
382  expr -= x.second;
383  c.add(expr == 0);
384  }
385 
386  // constraint (28): all matching-edges should be chosen!
387  DEBUG5(std::cout << "adding (28): all matching-edges should be chosen"<<std::endl);
388  for(auto x : vars.x)
389  if(I.is_matching_edge(x.first)) c.add(x.second == 1);
390 
391  // constraint (35),(36): there should be at most sigma_p paths & sigma_c cycles
392  DEBUG5(std::cout << "adding (35)&(36): there should be at most sigma_p paths & sigma_c cycles"<<std::endl);
393  {
394  IloExpr y_expr(env), z_expr(env);
395  for(auto y : vars.ys) y_expr += y.second;
396  for(auto z : vars.zs) z_expr += z.second;
397  c.add(y_expr <= (double)I.num_paths);
398  c.add(z_expr <= (double)I.num_cycles);
399  }
400 
401  // constraint (29-33): everything that comes into layer l should leave layer l
402  DEBUG5(std::cout << "adding (29-33): flow conservation"<<std::endl);
403  for(size_t l = 0; l < 3; ++l){
404  const unsigned prev_l = (l+1) % 2;
405  for(VertexIterRange<Graph> v = vertices(g); v.first != v.second; ++v.first){
406  if(l < 2) DEBUG5(std::cout << "for "<<VertexAndGraph<Graph>(*v.first, g)<<" in layer "<<l<<" adding\t\t 0 =");
407  IloExpr y_expr(env), z_expr(env);
408  for(AdjIterRange<Graph> nh = adjacent_vertices(*v.first, g); nh.first != nh.second; ++nh.first){
409  const VertexPair<Graph> vu = std::make_pair(*v.first, *nh.first);
410  const VertexPair<Graph> uv = std::make_pair(*nh.first, *v.first);
411  // remember: layer 0 -> 1 contains only matching edges
412  if( ((I.matched_with(*v.first) == *nh.first) == (l == 0)) && (l < 2)){
413  // flow goes to next layer along vu
414  y_expr += vars.y[l].at(vu);
415  DEBUG5(std::cout << " + y["<<l<<"]_"<<VertexPairAndGraph<Graph>(vu, vars.g));
416  // for z on layer 1, this means flow can go to layer 0 or layer 2
417  z_expr += vars.z[l].at(vu);
418  if(l == 1) z_expr += vars.z[2].at(vu);
419  }// if
420  if( (I.matched_with(*v.first) == *nh.first) == (prev_l == 0)){
421  if(l < 2){
422  // flow comes from the previous layer alog uv
423  y_expr -= vars.y[prev_l].at(uv);
424  DEBUG5(std::cout << " - y["<<prev_l<<"]_"<<VertexPairAndGraph<Graph>(uv, vars.g));
425  z_expr -= vars.z[prev_l].at(uv);
426  } else {
427  // for layer 2, flow comes up from layer 1 (stored in z[2])
428  z_expr -= vars.z[2].at(uv);
429  }
430  }// if
431  }// for
432  // on layer 1, p-flow can go up to tp, on layer 0, p-flow can come up from sp
433  if(l == 0) y_expr -= vars.ys.at(*v.first);
434  if(l == 0) DEBUG5(std::cout << " - ys_"<<VertexAndGraph<Graph>(*v.first, vars.g));
435  if(l == 1) y_expr += vars.yt.at(*v.first);
436  if(l == 1) DEBUG5(std::cout << "+ yt_"<<VertexAndGraph<Graph>(*v.first, vars.g));
437  // if l is 0, c-flow can come up from sc
438  if(l == 0) z_expr -= vars.zs.at(*v.first);
439  if(l == 2) z_expr += vars.zt.at(*v.first);
440  if(l < 2) DEBUG5(std::cout << std::endl);
441  if(l < 2) c.add(y_expr == 0);
442  c.add(z_expr == 0);
443  }// for
444  }// for
445 
446  // constraint (34): everything that comes from sc to v in layer 0 should go from v to tc in layer 2
447  DEBUG5(std::cout << "adding (34): cycle conservation"<<std::endl);
448  for(VertexIterRange<Graph> v = vertices(g); v.first != v.second; ++v.first){
449  IloExpr z_expr(env);
450  z_expr += vars.zs.at(*v.first);
451  z_expr -= vars.zt.at(*v.first);
452  c.add(z_expr == 0);
453  }
454 
455  // constraint (37,38): each subset S of vertices should contain at most |S|-1 endpoints of arcs
456  //DEBUG5(std::cout << "adding (37,38): each subset S of vertices should contain at most |S|-1 endpoints of arcs"<<std::endl);
457  // done via callback!
458  }
459 
460 
461  // compute the ILP formulation for a graph g
462  template<class Graph>
463  void populate_model(IloModel& model, IloEnv& env, var_collection<Graph>& vars, const Instance<Graph>& I){
464  const Graph& g(*I.g);
465  IloRangeArray c(env);
466  // construct variables, keeping note of the x_ij, y^l_ij and z^l_ij variables
467  DEBUG3(std::cout << "creating variables"<<std::endl);
468  populate_variables(env, vars, I);
469  // add optimization function
470  DEBUG3(std::cout << "creating optimization expression"<<std::endl);
471  IloExpr opt_exp(env);
472  for(EdgeIterRange<Graph> e = edges(g); e.first != e.second; ++e.first){
473  const Vertex<Graph>& u = source(*e.first, g);
474  const Vertex<Graph>& v = target(*e.first, g);
475  // get the appropriate x_ij variable
476  auto uv = vars.x.find(std::make_pair(u,v));
477  if(uv == vars.x.end()) uv = vars.x.find(std::make_pair(v,u));
478  assert(uv != vars.x.end());
479  // add the term weight(ij)*x_ij
480  opt_exp += (double)get(edge_weight, g, *e.first) * uv->second;
481  }
482  model.add(IloMaximize(env, opt_exp));
483  // construct constraints
484  DEBUG3(std::cout << "creating constraints"<<std::endl);
485  populate_constraints(env, c, vars, I);
486  model.add(c);
487  }
488 
489 }
490 
491 #endif
492 
Definition: read_adj_list.hpp:22
Definition: utils.hpp:96