Scaffolding  0.1
This program can assemble genome scaffolds using the pairing information in paired-end reads.
dp_table.hpp
1 
2 
3 #ifndef DP_TABLE_HPP
4 #define DP_TABLE_HPP
5 
6 
7 #include "utils/utils.hpp"
8 #include "utils/graph_typedefs.hpp"
10 
11 
12 namespace scaffold{ namespace solv{ namespace DP {
13 
14  typedef std::bitset<MAX_TW> DegMap;
15 
16  DegMap permute_degmap(const DegMap& d, const BytePermutation& perm)
17  {
18  DegMap result;
19  for(byte i = 0; i < MAX_TW; ++i)
20  if(d.test(i)) result.set(perm[i]);
21  return result;
22  }
23 
24  // check whether (d1,M1) and (d2,M2) are compatible
25  inline bool compatible(const DegMap& d1, const DegMap& M1, const DegMap& d2, const DegMap& M2){
26  return ((d1 ^ M1) & (d2 ^ M2)).none();
27  }
28 
29 
30  // the real table consists of 3 levels:
31  // level 1: map p,c to the solution using a PCMinMatrix
32  typedef PCMinMatrix<std::greater<size_t> > pc_to_sol;
33 
34  // level 2: map P to a pc_to_sol matrix
35  class P_to_pc_map;
36 
37  // level 3: map d to a P_to_pc_map
38  class d_to_P_map;
39 
40  // modify a permissive matching according to the insertion of edge uv
41  // return the number of paths and cycles that were closed by adding uv
42  PathsAndCycles modify_P_with_uv(PermissiveMatching& P, const byte u_idx, const byte du, const byte v_idx, const byte dv)
43  {
44  PathsAndCycles result;
45  // Case 2: d[u] = d[v] = 1:
46  // there is only the edge uv, so add uv to P
47  if((du == 1) && (dv == 1)){
48  // add uv to P and add the weight of uv to the weight of this entry; if this is impossible, delete this entry
49  assert(P[u_idx] == u_idx);
50  assert(P[v_idx] == v_idx);
51  P[u_idx] = v_idx;
52  P[v_idx] = u_idx;
53  }
54  // Case 3: d[u] = 2, d[v] = 1:
55  // there is a path x-u-v with x != v
56  if((du == 2) && (dv == 1)){
57  const byte x_idx = P[u_idx];
58  if(x_idx != u_idx){
59  assert(x_idx != v_idx);
60  // if x is deg-1, then extend xu to xv in P
61  P[v_idx] = x_idx;
62  P[x_idx] = v_idx;
63  // and clear P[u]
64  P[u_idx] = u_idx;
65  }
66  }
67  // Case 1: d[u] = 2, d[v] = 2
68  // there is a path p ending in u and a path q ending in v that we have to combine by inserting uv
69  if((du == 2) && (dv == 2)){
70  // get the vertices x and y that are paired with u and v, respectively, by P
71  const byte x_idx = P[u_idx];
72  const byte y_idx = P[v_idx];
73 
74  // TODO: optimize cases to reduce "if" checks
75 
76  // Case 1a: x = v & y = u, then adding uv closes a cycle
77  if(x_idx == v_idx){
78  assert(y_idx == u_idx);
79  result.c++;
80  }
81 
82  // Case 1c1: u is unpaired & v is paired
83  if((x_idx == u_idx) && (y_idx != v_idx)) P[y_idx] = y_idx;
84 
85  // Case 1c2: v is unpaired & u is paired
86  if((x_idx != u_idx) && (y_idx == v_idx)) P[x_idx] = x_idx;
87 
88  // Case 1d: x and y are different vertices with d[x] = d[y] = 1
89  if((x_idx != u_idx) && (x_idx != v_idx) && (y_idx != u_idx) && (y_idx != v_idx)){
90  P[x_idx] = y_idx;
91  P[y_idx] = x_idx;
92  }
93 
94  // Case 1b: u and v are unpaired
95  if((x_idx == u_idx) && (y_idx == v_idx)){
96  result.p++;
97  } else {
98  P[u_idx] = u_idx;
99  P[v_idx] = v_idx;
100  }
101  }// if
102  DEBUG4(std::cout << "new P = "<<P<<" and we closed "<<result<<" paths and cycles"<<std::endl);
103  return result;
104  }// function
105 
106  // level 2: map P to a pc_to_sol matrix
107  class P_to_pc_map : public unordered_map<PermissiveMatching, pc_to_sol*>
108  {
109  public:
110  using unordered_map<PermissiveMatching, pc_to_sol*>::iterator;
111  using unordered_map<PermissiveMatching, pc_to_sol*>::const_iterator;
112  using unordered_map<PermissiveMatching, pc_to_sol*>::erase;
113  using unordered_map<PermissiveMatching, pc_to_sol*>::empty;
114  using unordered_map<PermissiveMatching, pc_to_sol*>::emplace;
115  using unordered_map<PermissiveMatching, pc_to_sol*>::begin;
116  using unordered_map<PermissiveMatching, pc_to_sol*>::end;
117  using unordered_map<PermissiveMatching, pc_to_sol*>::find;
118  // forget a vertex in all permissive matchings of the map
119  P_to_pc_map* forget_vertex(const byte v_idx)
120  {
121  P_to_pc_map* const new_map = new P_to_pc_map();
122 
123  for(iterator old_i = begin(); old_i != end(); old_i = erase(old_i)){
124  const PermissiveMatching& P = old_i->first;
125  DEBUG5(std::cout << "constructing a new map @"<<new_map<<" by forgetting "<<(unsigned)v_idx<<" from P = "<<P<<std::endl);
126  // look where v is mapped in P
127  const byte u_idx = P[v_idx];
128  if(v_idx != u_idx){
129  // if v is mapped to some u != v, then create an entry where uv is replaced by uu
130  PermissiveMatching new_P(P);
131  new_P[u_idx] = u_idx;
132  new_P[v_idx] = v_idx;
133 
134  new_map->merge(new_P, old_i->second);
135  } else {
136  DEBUG5(std::cout << "forgetting "<<(unsigned)v_idx<<" closes a path in matrix @"<<old_i->second<<std::endl);
137  // if v is mapped to itself, then increase p in all pc entries
138  old_i->second->add_to_each_key(PathsAndCycles(1,0));
139  new_map->merge(P, old_i->second);
140  }// if
141  }// for
142  return new_map;
143  }// function
144 
145  // create a new P_to_pc_map that is the result of introducing an edge into us
146  P_to_pc_map* intro_edge(const byte u_idx, const byte v_idx, const byte du, const byte dv, const EdgeName& en, const size_t weight)
147  {
148  P_to_pc_map* const new_map = new P_to_pc_map();
149 
150  for(iterator old_i = begin(); old_i != end(); old_i = erase(old_i)){
151  const PermissiveMatching& old_P = old_i->first;
152  pc_to_sol* sol_matrix = old_i->second;
153 
154  // get P and modify it according to the degrees of u and v
155  PermissiveMatching P(old_P);
156  const PathsAndCycles closed_pc = modify_P_with_uv(P, u_idx, du, v_idx, dv);
157  DEBUG5(std::cout << "modified P:"<<std::endl<<old_P<<std::endl<<P<<" closing "<<closed_pc<<" pc's"<<std::endl);
158  // add the new edge to the matrix
159  sol_matrix->add_to_each_key(closed_pc);
160  sol_matrix->add_to_all(en, weight);
161 
162  // merge the result into the new map
163  new_map->merge(P, sol_matrix);
164  }// for
165  return new_map;
166  }// function
167 
168  // create a new P_to_pc_map that is the join of us and T
169  P_to_pc_map* join(const P_to_pc_map& T, const DegMap& new_deg2) const
170  {
171  P_to_pc_map* new_map = new P_to_pc_map();
172  // go through our and T's permissive matchings and try to join them up
173  for(const_iterator old_i = begin(); old_i != end(); ++old_i)
174  for(auto& T_Ppc: T){
175  const pc_to_sol* const my_matrix = old_i->second;
176  // merge the permissive matchings (should always be possible), getting the number of closed paths and cycles
177  PermissiveMatching P(old_i->first);
178  const PermissiveMatching& T_P(T_Ppc.first);
179  const pc_to_sol* const T_matrix = T_Ppc.second;
180 
181  DEBUG5(std::cout << "merging:"<<std::endl<<old_i->first<<" & "<<std::endl<<T_P<<" to "<<std::endl);
182  const PathsAndCycles closed_pc(P.merge_with(T_P, new_deg2));
183  DEBUG5(std::cout<<P<<std::endl);
184 
185 
186  // prepare solution matrix to hold the combination of matrices
187  pc_to_sol* pc = new pc_to_sol(my_matrix->max);
188  // go through our matrix and T's matrix and mix them with the paths & cycles created in the join of the matchings
189  for(auto my_pc = my_matrix->get_entries(); my_pc.first != my_pc.second; ++my_pc.first)
190  for(auto T_pc = T_matrix->get_entries(); T_pc.first != T_pc.second; ++T_pc.first){
191  DEBUG5(std::cout << "joining:"<< my_pc.first->first<<" & " << T_pc.first->first<<" --> "<< my_pc.first->first + T_pc.first->first + closed_pc<<std::endl);
192  MatrixEntry* ME = new MatrixEntry(*my_pc.first->second + *T_pc.first->second);
193  if(!pc->put(my_pc.first->first + T_pc.first->first + closed_pc,ME)) delete ME;
194  }// for
195  // merge the created entry into the container
196  new_map->merge(P, pc);
197  }// for
198  return new_map;
199  }// function
200 
201  // merge a new entry into a P_to_pc_maps
202  void merge(const PermissiveMatching& P, pc_to_sol* const pc)
203  {
204  if(pc->size()){
205  DEBUG5(std::cout << "merging "<<std::endl<<*pc<<" into "<<P<<std::endl);
206  iterator i = find(P);
207  if(i != end()){
208  DEBUG6(std::cout << "merging the matrix "<<std::endl<<*pc<<" with the present entry"<<std::endl<<*i->second<<" for P = "<<P<<std::endl);
209  // if there is already an entry for P in m, then merge the matrices
210  pc_to_sol* present_pc = i->second;
211  present_pc->destructive_merge(*pc);
212  delete pc;
213  } else {
214  DEBUG6(std::cout << "adding the matrix @"<<pc<<std::flush<<" (size "<<pc->size()<<") to P = "<<P<<std::endl);
215  emplace(P, pc);
216  }
217  } else {
218  DEBUG5(std::cout << "not merging now-empty matrix "<<std::endl);
219  delete pc;
220  }
221  }// function
222 
223  // merge a P_to_pc_map m, destroying it
224  void destructive_merge(P_to_pc_map& m)
225  {
226  DEBUG6(std::cout << "destructively merging "<<m.size()<<" matrices"<<std::endl);
227  for(iterator i = m.begin(); i != m.end(); i = m.erase(i)) {
228  merge(i->first, i->second);
229  }
230  }
231 
232  // copy a P_to_pc_map to another
233  void make_copy(P_to_pc_map& target)
234  {
235  for(iterator i = begin(); i != end(); ++i){
236  DEBUG5(std::cout << "copying matrix with P = "<<i->first<<" @"<<i->second<<" (size "<<i->second->size()<<")"<<std::endl);
237  // create a new matrix as copy of the old one
238  pc_to_sol* pc = new pc_to_sol(*i->second);
239  // add it with the same permissive matching as in source
240  target.emplace(i->first, pc);
241  }
242  }
243 
244  // apply the BytePermutation to each P, destroying the map
245  P_to_pc_map* apply_permutation(const BytePermutation& perm)
246  {
247  P_to_pc_map* new_map = new P_to_pc_map();
248 
249  for(iterator i = begin(); i != end(); i = erase(i)){
250  PermissiveMatching P(i->first);
251  P.permute(perm);
252  new_map->emplace(P, i->second);
253  }
254  return new_map;
255  }
256 
257 
258  friend std::ostream& operator<<(std::ostream& os, const P_to_pc_map& M)
259  {
260  for(auto i = M.begin(); i != M.end(); ++i) os <<"\t\t\t\t"<<i->first<<":"<<std::endl<< *i->second << std::endl;
261  return os;
262  }
263 
264  };
265 
266 
267  // level 3: map d to a P_to_pc_map
268  class d_to_P_map : public unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >
269  {
270  public:
271  using unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >::iterator;
272  using unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >::erase;
273  using unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >::emplace;
274  using unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >::begin;
275  using unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >::end;
276  using unordered_map<DegMap, P_to_pc_map*, std::hash<DegMap> >::find;
277  // forget a vertex in all permissive matchings of the map
278  d_to_P_map* forget_vertex(const byte v_idx)
279  {
280  d_to_P_map* const new_map = new d_to_P_map();
281 
282  for(iterator old_i = begin(); old_i != end(); old_i = erase(old_i)){
283  const DegMap& d = old_i->first;
284  // stuff happens only if degree of v is one
285  if(d.test(v_idx)){
286  DegMap new_d = d;
287  new_d.reset(v_idx);
288 
289  DEBUG4(std::cout << "forgetting "<<(unsigned)v_idx<<" from entry with d = "<<d<<" (new d = "<<new_d<<")"<<std::endl);
290 
291  P_to_pc_map* old_Ppc_map = old_i->second;
292  P_to_pc_map* new_Ppc_map = old_Ppc_map->forget_vertex(v_idx);
293  // exchange the old map for the new map
294  delete old_Ppc_map;
295  old_i->second = NULL;
296 
297  // merge the new d entry into the new table
298  new_map->merge(new_d, new_Ppc_map);
299  } else new_map->merge(d, old_i->second);
300  }// for
301  return new_map;
302  }// function
303 
304  // add an edge to all permissive matchings and the matrices of the map
305  d_to_P_map* intro_edge(byte u_idx, byte v_idx, const bool mu, const bool mv, const bool mu_old, const bool mv_old, const bool is_matching_edge, const EdgeName& en, const size_t weight)
306  {
307  d_to_P_map* const new_map = new d_to_P_map();
308 
309  // Step 1: if uv is not a matching edge, then copy the old entries into the new table, corresponding to not taking the edge uv
310  if(!is_matching_edge){
311  DEBUG4(std::cout << "making a normal copy of the table to represent not-taking the edge ("<<en.first<<","<<en.second<<")"<<std::endl);
312  // TODO: don't make a copy if we know that the old entry will be thrown away anyways
313  make_copy(*new_map);
314  }
315 
316  // Step 2: add the edge to each entry and merge the results into the new table
317  for(iterator old_i = begin(); old_i != end(); old_i = erase(old_i)){
318  const DegMap& d = old_i->first;
319 
320  // to take the edge, make sure that: if it's not a matching edge, then the non-matching degree of u and v are 0
321  if(is_matching_edge || ((mu_old == d.test(u_idx)) && (mv_old == d.test(v_idx)))){
322  DEBUG4(std::cout << "taking "<<(is_matching_edge?"M-":" ")<<"edge ("<<en.first<<","<<en.second<<") with indices ("<<(unsigned)u_idx<<","<<(unsigned)v_idx<<") & old M-values ("<<mu_old<<","<<mv_old<<") for d = "<<d<<std::endl);
323  DegMap new_d = d;
324  // Step 2a: increase both d[u] and d[v]
325  new_d.flip(u_idx);
326  new_d.flip(v_idx);
327 
328  byte du = mu + (new_d.test(u_idx) != mu);
329  byte dv = mv + (new_d.test(v_idx) != mv);
330  // assert d[u] >= d[v]
331  if(du < dv) {
332  std::swap(u_idx, v_idx);
333  std::swap(du, dv);
334  }
335 
336  // Step 2b: introduce the edge into the Permissive Matchings and Matrices
337  P_to_pc_map* old_Ppc = old_i->second;
338  P_to_pc_map* new_Ppc = old_Ppc->intro_edge(u_idx, v_idx, du, dv, en, weight);
339 
340  delete old_Ppc;
341  old_i->second = NULL;
342  // Step 2c: merge the new entry into the table
343  new_map->merge(new_d, new_Ppc);
344  }// if
345  }// for
346  return new_map;
347  }// function
348 
349  d_to_P_map* join(const d_to_P_map& T, const DegMap& old_M, const DegMap& T_M)
350  {
351  d_to_P_map* result = new d_to_P_map();
352  // go through our table...
353  for(iterator old_i = begin(); old_i != end(); old_i = erase(old_i)){
354  // save our degrees
355  const DegMap& my_d = old_i->first;
356  P_to_pc_map* const old_Ppc = old_i->second;
357  // go through T's table
358  for(auto& T_dPpc: T){
359  // save T's degrees
360  const DegMap& T_d = T_dPpc.first;
361  // check if the degrees are compatible
362  if(compatible(my_d, old_M, T_d, T_M)){
363  const P_to_pc_map& T_Ppc = *T_dPpc.second;
364  DEBUG5(std::cout << "--> merging d's:"<<std::endl<<my_d<<" ("<<old_Ppc->size()<<" P's) & "<< std::endl<<T_d<<" ("<<T_Ppc.size() <<" P's)"<<std::endl);
365  // save the set of vertices who became degree-2 in the join
366  const DegMap& new_deg2 = my_d & T_d;
367  // produce the new degrees as the sum of the old ones
368  DegMap new_d = my_d ^ T_d;
369  // prepare the container to hold the merge of the P_to_pc_maps corresponding to my_d and T_d
370  P_to_pc_map* new_Ppc = old_Ppc->join(T_Ppc, new_deg2);
371  // merge the combined P_to_pc_maps into the new table
372  result->merge( new_d, new_Ppc);
373  }// if
374  }// for (T's table)
375  // once we combined old_Ppc with all P entries of T, deep-delete it
376  for(auto i = old_Ppc->begin(); i != old_Ppc->end(); ++i) delete i->second;
377  delete old_Ppc;
378  old_i->second = NULL;
379  }// for (our table)
380  return result;
381  }
382 
383  // merge a new entry into a d_to_P_map
384  void merge(const DegMap& d, P_to_pc_map* const Ppc)
385  {
386  if(!Ppc->empty()){
387  iterator i = find(d);
388  if(i != end()){
389  DEBUG6(std::cout << "merging the map @"<<Ppc<<" with the present entry (@"<<i->second<<") for d = "<<d<<std::endl);
390  // if there is already an entry for d in m, then merge the maps
391  P_to_pc_map* present_Ppc = i->second;
392  present_Ppc->destructive_merge(*Ppc);
393  delete Ppc;
394  } else emplace(d, Ppc);
395  } else {
396  DEBUG5(std::cout << "not merging empty P_to_pc map into d = "<<d<<std::endl);
397  delete Ppc;
398  }
399  }// function
400 
401  // deep-copy a d_to_P_map to another
402  void make_copy(d_to_P_map& target)
403  {
404  for(iterator i = begin(); i != end(); ++i){
405  DEBUG5(std::cout << "deep-copying entry with d = "<<i->first<<" & map @"<<i->second<<std::endl);
406  // create a new P_to_pc_map as copy of the old one
407  P_to_pc_map* Ppc = new P_to_pc_map();
408  i->second->make_copy(*Ppc);
409  // add it with the same DegMap as in source
410  target.emplace(i->first, Ppc);
411  }
412  }
413 
414  // apply a BytePermutation to each d and each P, destroying the current map
415  d_to_P_map* apply_permutation(const BytePermutation& perm)
416  {
417  d_to_P_map* new_map = new d_to_P_map();
418 
419  for(iterator i = begin(); i != end(); i = erase(i)){
420  DegMap d = permute_degmap(i->first, perm);
421  P_to_pc_map* new_Ppc = i->second->apply_permutation(perm);
422 
423  // note: we can use emplace here, because no conflicts can arise from applying a permutation
424  new_map->emplace(d, new_Ppc);
425  }// for
426  return new_map;
427  }
428 
429 
430  friend std::ostream& operator<<(std::ostream& os, const d_to_P_map& M)
431  {
432  for(auto i = M.begin(); i != M.end(); ++i) os <<"\t\t"<<i->first<<":"<<std::endl<< *i->second << std::endl;
433  return os;
434  }
435 
436  };
437 
438 
439 
440 
441 
442 
443 
444 
445 
446  template<class Graph>
447  class DP_Table
448  {
449  const Instance<Graph>& I;
450 
451  // the subgraph of introduced edges
452  //TD_Subgraph<Graph> g;
453 
454  public:
455  // index of vertices used; TODO: use an array instead of the unordered_set_of<byte>
456  typedef boost::bimap< boost::bimaps::unordered_set_of<Vertex<Graph> >, boost::bimaps::unordered_set_of<byte> > VertexIndex;
457  VertexIndex* index;
458 
459  // a bitset of vertices that are incident to edges of M that have been introduced in this subtree
460  DegMap M_adj;
461 
462  typedef d_to_P_map DP_Entries;
463  DP_Entries* table;
464 
465  // contstructing the index from the vertex set
466  void construct_index(const VertexSet<Graph>& VSet)
467  {
468  for(auto& v : VSet) intro_vertex(v);
469  }
470 
471  public:
472  // constructors
473  DP_Table(const Instance<Graph>& _I, const VertexSet<Graph>& VSet):
474  I(_I),// g(*I.g),
475  index(new VertexIndex()), table(new DP_Entries())
476  {
477  construct_index(VSet);
478  }
479  // given a TOL Vertexset, convert it to a set of Vertex<Graph>'s
480  DP_Table(const Instance<Graph>& _I, const TOL::GraphVertexSet& VSet, TOL::VTranslateBoostTOL<Graph>* vtranslate):
481  I(_I),// g(*I.g),
482  index(new VertexIndex()), table(new DP_Entries())
483  {
484  VertexSet<Graph> good_vset;
485  for(auto& v: VSet) good_vset.emplace(vtranslate->right.at(v));
486  construct_index(good_vset);
487  }
488 
489  // destructor
490  ~DP_Table(){ delete table; delete index; }
491 
492 
493  // clear the table, freeing all memory helt
494  void clear()
495  {
496  for(auto i = table->begin(); i != table->end(); ++i){
497  for(auto j = i->second->begin(); j != i->second->end(); ++j) delete j->second;
498  i->second->clear();
499  delete i->second;
500  }
501  table->clear();
502  }
503 
504  // return whether this is a fresh table, without content
505  bool empty() const
506  {
507  return table->empty();
508  }
509 
510  void get_VSet(std::list<Vertex<Graph> >& l) const
511  {
512  for(auto& i: index->left) l.emplace_back(i.first);
513  }
514 
515 
516  // ==========================
517  // ===== DP OPERATIONS ======
518  // ==========================
519  // always take care of: index, free_indices, g, M_adj and the table
520 
521  // introduce a vertex
522  void intro_vertex(const Vertex<Graph>& v)
523  {
524  DEBUG3(std::cout << "introducing new vertex "<<VertexAndGraph<Graph>(v, *I.g)<<std::endl);
525  // index & free_indices
526  // try to insert the vertex at name % MAX_TW; if vertices don't have names use ((size_t)v % MAX_TW)
527  byte v_idx = get(vertex_name, *I.g, v) % MAX_TW;
528  // if there is already such an index, find the next free index
529  while(contains(index->right, v_idx)) v_idx = (v_idx + 1) % MAX_TW;
530  index->left.insert(std::make_pair(v, v_idx));
531  // g
532  //g.introduce_vertex(v);
533  // M_adj & table do not change since no edges are incident with v yet
534  }
535  void intro_vertices(const VertexSet<Graph>& V)
536  {
537  for(auto& v : V) intro_vertex(v);
538  }
539 
540 
541  // forget a vertex
542  void forget_vertex_from_table(const byte& v_idx)
543  {
544  DP_Entries* const old_table = table;
545  table = old_table->forget_vertex(v_idx);
546  delete old_table;
547  DEBUG5(std::cout << "table after forgetting "<<(unsigned)v_idx<<":"<<std::endl<<*table<<std::endl);
548  }// function
549  void forget_vertex(const Vertex<Graph>& v)
550  {
551  // index
552  const auto i = index->left.find(v);
553  assert(i != index->left.end());
554  const byte v_idx = i->second;
555  DEBUG5(std::cout<< "forgetting vertex["<<(unsigned)v_idx<<"] = "<< std::flush<<VertexAndGraph<Graph>(index->right.at(v_idx), *I.g)<<std::endl);
556  index->left.erase(i);
557 
558  // g
559  //g.forget_vertex(v);
560 
561  forget_vertex_from_table(v_idx);
562  // M_adj
563  M_adj.reset(v_idx);
564  }
565  void forget_vertices(const VertexSet<Graph>& V)
566  {
567  for(auto& v : V) forget_vertex(v);
568  }
569 
570 
571  // introduce a set of edges & set M_adj, remember d = degree % 2
572  void intro_edge_to_table(byte u_idx, byte v_idx, const bool is_matching_edge, const EdgeName& en, const size_t weight)
573  {
574  bool mu, mv;
575  bool mu_old = M_adj.test(u_idx);
576  bool mv_old = M_adj.test(v_idx);
577 
578  if(is_matching_edge) {
579  assert(!mu_old && !mv_old);
580  M_adj.set(u_idx);
581  M_adj.set(v_idx);
582  mu = mv = true;
583  } else {
584  mu = mu_old;
585  mv = mv_old;
586  }
587  DEBUG4(std::cout << "new M = "<<M_adj<<std::endl);
588 
589  // setup a new table
590  DP_Entries* old_table = table;
591  table = old_table->intro_edge(u_idx, v_idx, mu, mv, mu_old, mv_old, is_matching_edge, en, weight);
592  delete old_table;
593  }// function
594  void intro_edge(const Edge<Graph>& e)
595  {
596  DEBUG4(std::cout << "introducing edge "<<EdgeAndGraph<Graph>(e, *I.g)<<std::endl);
597  // index & free_indices don't change
598 
599  // g
600  //g.introduce_edge(e);
601 
602  const bool is_in_M = I.is_matching_edge(e);
603  const Vertex<Graph> u = source(e, *I.g);
604  const Vertex<Graph> v = target(e, *I.g);
605  const auto iu = index->left.find(u);
606  const auto iv = index->left.find(v);
607  assert(iu != index->left.end());
608  assert(iv != index->left.end());
609  const byte u_idx = iu->second;
610  const byte v_idx = iv->second;
611 
612  // M_adj & table
613  intro_edge_to_table(u_idx, v_idx, is_in_M, EdgeName(get(vertex_name, *I.g, u), get(vertex_name, *I.g, v)) , get(edge_weight, *I.g, e));
614  }
615  void intro_edges(const std::list<Edge<Graph> >& E)
616  {
617  for(auto& e : E) intro_edge(e);
618  }
619 
620 
621  // make our indices compatible with the indices of T, that is, reorder our indices such that all our vertices have the same index here as in T
622  void unify_indices(const DP_Table& T)
623  {
624  BytePermutation perm;
625  // Step 1: compute the index permutation
626  for(const auto& i : index->left){
627  const Vertex<Graph>& v = i.first;
628  const byte v_idx = i.second;
629 
630  perm[v_idx] = T.index->left.at(v);
631  }
632  if(!perm.is_identity()){
633  DEBUG3(std::cout << "remapping indices with permutation "<<perm<<std::endl);
634  // Step 2: apply the permutation to the index
635  VertexIndex* new_index = new VertexIndex;
636  for(const auto& i : index->left)
637  new_index->insert(typename VertexIndex::value_type(i.first, perm[i.second]));
638  delete index;
639  index = new_index;
640  // Step 3: remap M
641  M_adj = permute_degmap(M_adj, perm);
642  // Step 4: apply the permutation to the table
643  DP_Entries* new_table = table->apply_permutation(perm);
644  table = new_table;
645  } else DEBUG3(std::cout << "rejoice, the indices are identical, saving the remap!"<<std::endl);
646  }
647 
648 
649  // join table with child table
650  void join(DP_Table& T)
651  {
652  // TODO: test whether an index array for index-translation is faster than unifying the indices
653  // TODO: try to insert a vertex each time at the same index, so that tables are inheritently compatible!
654  // make indices compatible
655  if(index->size() < T.index->size()) unify_indices(T); else T.unify_indices(*this);
656  // unite the subgraphs
657  //g.join(T.g);
658  // save the old table to work with
659  DP_Entries* old_table = table;
660  // if we don't have table, then just steal the table of T and its M_adj
661  if(table->empty()){
662  DEBUG4(std::cout << "--> stealing size-"<<T.table->size()<<" table from child"<<std::endl);
663  delete table;
664  table = T.table;
665  T.table = new DP_Entries();
666 
667  M_adj = T.M_adj;
668  DEBUG4(std::cout << "--> new M = "<<M_adj<<std::endl);
669  } else {
670  DegMap old_M = M_adj;
671  // wipe the table clean & merge matchings
672 
673  // update the matching
674  M_adj |= T.M_adj;
675  DEBUG4(std::cout << "--> new M = "<<M_adj<<std::endl);
676 
677  table = old_table->join(*T.table, old_M, T.M_adj);
678  delete old_table;
679  }// if
680  }// function
681 
682  // initialize this table as a leaf-table
683  void init_as_leaf()
684  {
685  DEBUG5(std::cout << "--> initializing leaf"<<std::endl);
686  typename d_to_P_map::iterator dPpc_i = table->emplace(DegMap(), new P_to_pc_map()).first;
687  typename P_to_pc_map::iterator Ppc_i = dPpc_i->second->emplace(PermissiveMatching(), new pc_to_sol(I.num_paths, I.num_cycles)).first;
688  pc_to_sol& leaf_matrix = *Ppc_i->second;
689  leaf_matrix.put_empty(PathsAndCycles(0,0));
690  }
691 
692  // return the size in MatrixEntries
693  size_t size() const
694  {
695  size_t result = 0;
696  for(auto& i : *table)
697  for(auto& j : *i.second)
698  result += j.second->size();
699  return result;
700  }
701 
702 
703  // read a solution from the table
704  void read_solution(DynProgSolution<std::greater<size_t> >& S){
705  for(auto& dPpc: *table)
706  for(auto& Ppc: *dPpc.second)
707  for(auto pc = Ppc.second->get_entries(); pc.first != pc.second; ++pc.first)
708  S.put(pc.first->first, pc.first->second);
709  }
710 
711  friend std::ostream& operator<<(std::ostream& os, const DP_Table& T)
712  {
713  for(typename DP_Entries::iterator i = T.table->begin(); i != T.table->end(); ++i) os <<i->first<<":"<<std::endl<< *i->second << std::endl;
714  return os;
715  }
716  }; // class DP_Table
717 
718 }}}// namespace
719 
720 
721 #endif
722 
bool is_identity() const
return whether everyone matches to itself
Definition: permissive_matching.hpp:98
PathsAndCycles merge_with(const PermissiveMatching &P, const std::bitset< ARRAY_LENGTH > &deg1_in_both)
TODO: move this out of the permissive matching class as it's unique to the DP code & this should be a...
Definition: permissive_matching.hpp:127
Definition: read_adj_list.hpp:22
unsigned num_cycles
max number of cycles in solutions
Definition: instance.hpp:33
Definition: dp_table.hpp:107
Definition: dp_solution.hpp:19
Definition: permissive_matching.hpp:25
void permute(const BytePermutation &perm)
rename the indices according to the given BytePermutation
Definition: permissive_matching.hpp:111
Definition: dp_table.hpp:447
unsigned num_paths
max number of paths in solutions
Definition: instance.hpp:32
bool contains(const Set &s, const Element &el)
a more readable containment check
Definition: utils.hpp:171
Definition: min_matrix.hpp:36
Definition: graph_typedefs.hpp:26
Definition: dp_table.hpp:268