src/max_weight_branch.cc
6fe809cf
 /*
   max_weight_branch.c
 
   Version : 1.1
   Author  : Niko Beerenwinkel
   
   (c) Max-Planck-Institut fuer Informatik, 2004
 */
 
 
 #include "include/max_weight_branch.h"
 
 
 // global variables:
 
 static map<node,string> Mut;  // node labels
 static map<edge,double> c;    // edge weights
 
 static array< array<node> > cycle_contr;
 // cycle_contr[i][k] == v_C <==> the k-th cycle C in B[i] has been contracted to v_C in G[i+1]
 
 static array< array<edge> > cheapest_edge;
 // cheapest_edge[i][k] is some cheapest edge on the k-th cycle in B[i]
 
 static map<edge,edge> Phi;
 // Phi[e'] == e  <==> e in G[i] has been contracted to e' in G[i+1]
 
 static array< array< map<edge,edge> > > alpha;  
 // e = (z, y), z not in C, y in C  <==>  alpha[e] == pred of y in C 
 
 
 
 // functions:
 
 int compare_weights(const edge& e1, const edge& e2)
 {
   if (c[e1] < c[e2])  return -1;
   if (c[e1] > c[e2])  return  1;
   return 0;
 }
 
 
 
 double BRANCHING_WEIGHT(list<edge>& B, edge_array<double>& weight)
 {
   // total weight of a branching
   
   double total_weight = 0;
   edge e;
 
   forall(e, B)
     total_weight += weight[e];
 
   return total_weight;
 }
 
 
 
 void UNCOVER_BRANCHING(graph& G, list<edge>& B)
 {
   // turn G into the branching defined by B (B \subset E(G))
 
   edge e;
 
   edge_set E_B(G);  // edge set of B
 
   forall(e, B)
     E_B.insert(e);
 
   edge_set T_D(G); //edges to delete
 
   forall_edges(e, G)
     if (! E_B.member(e))
 	T_D.insert(e);
       //G.del_edge(e);
 
   for(edge_set::iterator it = T_D.begin(); it != T_D.end(); ++it)
       G.del_edge(*it);
 
 }
 
 
 
 void DOT(graph& G, map<node,string>& mut, map<edge,double>& cond_prob, char *filestem)
 {
   // produces output in dot format (graphviz package)
   // see http://www.research.att.com/sw/tools/graphviz/
 
   node v;  edge e;
 
   char filename[128];
   sprintf(filename, "%s.dot", filestem);
   
   std::ofstream dotout(filename);
   dotout << "digraph MWB {" << std::endl << std::endl;
   
   forall_nodes(v, G)
     {
       dotout << "\t \"" << v << "\"";
       dotout << " [ label=\"" << mut[v] << "\", shape=\"plaintext\", height=\"0.3\", fontsize=\"12\", style=\"filled\", fillcolor=\"white\" ];" << std::endl;
     }
   dotout << std::endl;
 
   forall_edges(e, G)
     {
       node s = G.source(e);
       node t = G.target(e);
       dotout.precision(2);
       dotout << std::showpoint;
       dotout << "\t \"" << s << "\" -> \"" << t << "\"";
       dotout << " [ fontsize=\"10\", label=\"" << cond_prob[e] << "\" ];" << std::endl;
     }
 
   dotout << "}" << std::endl;
   dotout.close();
 }
 
 
 double branching_weight_intern(list<edge>& B)
 {
   // total weight of a branching
   
   double w = 0;
 
   edge e;
   forall(e, B)
     w += c[e];
   
   return w;
 }
 
 
 
 list<edge> max_weight_subgraph_indeg_le_1(graph& G)
 {
   // find maximum weight subgraph of G with indeg <= 1 for all v in V(G)
   // a list of edges in G of this subgraph is returned
   
   node v;
   list<edge> B;
 
   forall_nodes(v, G)  // choose heaviest inedge
     {
       list<edge> L = G.in_edges(v);
       if (! L.empty())
 	B.append(L.contents(L.max(*compare_weights)));
     }
 
   return B;
 }
 
 
 array< list<edge> > all_cycles(graph& G, list<edge>& B)
 {
   // find all cycles in B
 
   edge e;
 
   array< list<edge> > CA;  // array of cycles
   int k = -1;              // cycle index
 
   // construct subgraph:
   GRAPH<node,edge> G_B;  // the subgraph of G induced by B
   map<node,node> proj;   // proj : V(G) -->> V(G_B)
 
   forall(e, B)
     {
       node s = G.source(e);
       if (! proj.defined(s))
 	{
 	  node s_G = G_B.new_node();
 	  G_B[s_G] = s;  // needed?
 	  proj[s] = s_G;
 	}
       node t = G.target(e);
       if (! proj.defined(t))
 	{
 	  node t_G = G_B.new_node();
 	  G_B[t_G] = t;  // needed?
 	  proj[t] = t_G;
 	}
       G_B[G_B.new_edge(proj[s], proj[t])] = e;
     }
   
   // identify cycles in G_B:
   list<edge> CEL;  // cycle edge list, 
   // will contain one edge (in G_B) from each cycle after Is_Acyclic call
 
   if (! Is_Acyclic(G_B, CEL))
     {
       edge first_e;
       forall(first_e, CEL)
 	{
  	  list<edge> C;  // a cycle is stored as the list of its edges in G
 	  
 	  // iterate over cycle following inedges:
 	  node s = G_B.target(first_e);
 	  node first_v = s;  // starting node;
 	  edge e = NULL; //edge e = nil;
 	  while (s != first_v || e == NULL)//nil)
 	    {
 	      e = G_B.in_edges(s).head();
 	      s = G_B.source(e);  // move on
 	      C.push(G_B[e]);  // store corresponding edge in G (!)
 	      // the order in C follows the edge directions
 	    }
 
 	  k++;  CA.resize(k+1);
  	  CA[k] = C;
  	}
     }
   
   return CA;
 }
 
 
 
 edge predecessor_in_cycle(node y, list<edge>& C)
 {
   // predecessor edge of y in C
   
   edge e;
   forall(e, C)
     {
       if (target(e) == y)
 	return e;
     }
 
   return NULL; //nil;
 }
 
 
 void contract_cycle_edge(edge& e, double alpha_cost, double cheapest_cost, GRAPH<node,edge>& H, node& v_C, map<edge,edge>& edge_contr, node_set& VC)
 {
   // note:  e \in E(H)
 
   node s = H.source(e);  // \in G(H)
   node t = H.target(e);  // \in G(H)
 
   if (VC.member(s) && (! VC.member(t)))  // e leaves C
     {
       edge e_tilde = H.new_edge(v_C, t);  // new edge
       c[e_tilde] = c[e];
       edge_contr[H[e]] = e_tilde;
 
       H[e_tilde] = H[e];  // update
       Phi[e_tilde] = H[e];
 
       H.del_edge(e);
     }
 
   if ((! VC.member(s)) && VC.member(t))  // e enters C
     {
       edge e_prime = H.new_edge(s, v_C);  // new edge
       c[e_prime] = c[e] - alpha_cost + cheapest_cost;
       edge_contr[H[e]] = e_prime;
 
       H[e_prime] = H[e];  // update
       Phi[e_prime] = H[e];
 
       H.del_edge(e);
     }
 
   if (VC.member(s) && VC.member(t))  // e is in C
     H.del_edge(e);
   
 }
 
 
 
 string contract_cycle_node(node& v, GRAPH<node,edge>& H, node& v_C, map<node,node>& node_contr, node_set& VC)
 {
   string label;
 
   if (VC.member(v))  // v is on C
     {
       label += Mut[v];
       H.del_node(v);
       node_contr[H[v]] = v_C;
     }
   
   return label;
 }
 
 
 
 void contract_cycle(int i, array< list<edge> >& CA, int k, GRAPH<node,edge>& H, map<node,node>& node_contr, map<edge,edge>& edge_contr)
 {
   node v;  edge e;
 
   list<edge> C = CA[k];  // cycle to be contracted (indexed by k)
   
   // node set in H indiced by cycle (in G):
   node_set VC(H);  // V(C) \subset H
   forall(e, C)
     {
       VC.insert(H.source(edge_contr[e]));
       VC.insert(H.target(edge_contr[e]));
     }
   
   // some cheapest edge on C
   cheapest_edge.resize(i+1);  cheapest_edge[i].resize(k+1);
   cheapest_edge[i][k] = C.contents(C.min(*compare_weights));
   
   // new node v_C for contracted cycle C
   node v_C = H.new_node();
   cycle_contr.resize(i+1);  cycle_contr[i].resize(k+1);
   cycle_contr[i][k] = v_C;  // in G[i+1]
 
   // contract edges in H
   list<edge> EL = H.all_edges(); 
   forall(e, EL)
     {
       alpha.resize(i+1);  alpha[i].resize(k+1);
       alpha[i][k][H[e]] = predecessor_in_cycle(target(H[e]), C);  // predecessor edge of target(e) in C
       contract_cycle_edge(e, c[alpha[i][k][H[e]]], c[cheapest_edge[i][k]], H, v_C, edge_contr, VC);
     }
   
   // contract nodes in H
   string new_label("(");
   list<node> NL = H.all_nodes();
   forall(v, NL)
     new_label += contract_cycle_node(v, H, v_C, node_contr, VC);
   Mut[v_C] = new_label + ")";
 
 }
 
 
 
 void contract_all_cycles(graph& G, int i, array< list<edge> > CL, GRAPH<node,edge>& H)
 {
   // construct the contraction (G, c) --> (H, c)
 
   node v;  edge e;
   
   // {node, edge}_contr : (G, c) -->> (H, c')
   map<node,node> node_contr;  // node contraction map
   map<edge,edge> edge_contr;  // edge contraction map
 
   // initialize as identity map
   forall_nodes(v, G)
     {
       node_contr[v] = H.new_node();
       H[node_contr[v]] = v;
       Mut[node_contr[v]] = Mut[v];  // labels
     } 
   forall_edges(e, G)
     {
       edge_contr[e] = H.new_edge(node_contr[G.source(e)], node_contr[G.target(e)]);
       H[edge_contr[e]] = e;
       c[edge_contr[e]] = c[e];  // weights
     }
 
   // contract cycles in H
   for (int k=CL.low(); k<=CL.high(); k++)
     {
       contract_cycle(i, CL, k, H, node_contr, edge_contr);
       list<edge> empty_list;
     }
 }
 
 
 
 void reconstruct_branching(int i, GRAPH<node,edge>& H, list<edge>& B_H, list<edge>& B_G, array< list<edge> >& CA)
 {
   //  reconstruct branching B_G from the contraction
   //  (G, B_G==B[i-1]) --> (H==G[i], B_H==B[i]) 
   //  CA is the array of cycles in G
 
   edge e;
   
   B_G.clear();
   
   node_set CCS(H);  // contracted cycles in H
   for (int k=CA.low(); k<=CA.high(); k++)
     CCS.insert(cycle_contr[i-1][k]);
   
   // E(B_G) := E(B_H) \ {e_prime=(z, v_C) | z \in V(B_H), C cycle in B_G}
   forall(e, B_H)
     if (! CCS.member(H.target(e))) 
       B_G.append(H[e]);
  
   // check all cycles in B_G
   for (int k=CA.high(); k>=CA.low(); k--)
     {
       list<edge> C = CA[k];  // cycle edges
       
       // look for e'==(z, v_C) in B_H
       edge e_prime = NULL; //nil;
       forall(e, B_H)
 	if (H.target(e) == cycle_contr[i-1][k])  
 	  e_prime = e;
       
       if (e_prime != NULL) //nil)  // e' == (z, v_C) in B_H
 	{
 	  B_G.append(Phi[e_prime]);
 	  forall(e, C)
 	    if (e != alpha[i-1][k][Phi[e_prime]])
 	      B_G.append(e);
 	}
       else  // no edge (z, v_C) in B_H
 	{
 	  forall(e, C)
 	    if (e != cheapest_edge[i-1][k])
 	      B_G.append(e);
 	}
       
     }
 }
 
 
 
 list<edge> MAX_WEIGHT_BRANCHING(graph& G0, map<node,string>& node_label, edge_array<double>& weight)
 {
   // Compute a maximum weight branching of the weighted digraph (G, weight)
   // The list of edges of the branching is returned.
   // The algorithm with all notation is taken from the book
   // Korte, Vygen: Combinatorial Optimization, Springer 2000, pp. 121-125
 
   node v;  edge e;
 
   // step 0: data structures:
   array< GRAPH<node,edge> > G(1);  // G[i+1] is subgraph of G[i]
   array< list<edge> > B(1);  // B[i] \subset E(G[i])
   array< array< list<edge> > > CAA(1);  // array of cycle arrays, each cycle is a subset of B[i]
   
   // step 1: initialization.
   CopyGraph(G[0], G0);  
   forall_edges(e, G[0])  // edge weights
     c[e] = weight[G[0][e]];
 
   forall_nodes(v, G[0])  // node labels
     Mut[v] = node_label[G[0][v]];
 
   // step 2: construct greedy subgraph B[i].
   B[0] = max_weight_subgraph_indeg_le_1(G[0]);
 
   // step 3: for all cycles in B[i].
   CAA[0] = all_cycles(G[0], B[0]);
 
   int i = 0;
   while (CAA[i].size() > 0)
     {
       // step 4: construct (G[i+1], c[i+1]) from (G[i], c[i]).
       G.resize(i+2);  B.resize(i+2);  CAA.resize(i+2);
 
       contract_all_cycles(G[i], i, CAA[i], G[i+1]);
 
       i++;
       B[i] = max_weight_subgraph_indeg_le_1(G[i]);  // (step 2)
 
       CAA[i] = all_cycles(G[i], B[i]);  // (step 3)
     }
   
   // step 5+6: reconstruct the maximum branching B
   while (i > 0)
     {
       reconstruct_branching(i, G[i], B[i], B[i-1], CAA[i-1]);
       i--;
     }
 
   list<edge> B0;
   forall(e, B[i]){
     B0.append(G[i][e]);
   }
 
   //clear the global static variables
   Mut.clear();
   c.clear();
   cycle_contr.clear();
   cheapest_edge.clear();
   Phi.clear();
   alpha.clear();
 
   return B0;
 }